# Is there a way to compute Tanget attribute for a mesh simiar to compute normals

I need to add tangent attribute to my mesh, but couldn’t find how to calculate it. Vertex data has compute normals method is there any similar helper for tangent?
I tried creating custom one but unable to get a proper results.

``````computeTangents() {
const index = this.getIndices();
const positionAttributes = this.getVerticesData(VertexBuffer.PositionKind);
const normalAttributes = this.getVerticesData(VertexBuffer.NormalKind);
const uvAttributes = this.getVerticesData(VertexBuffer.UVKind);

const tangetAttributes = this.getVerticesData(VertexBuffer.TangentKind);

if (!index || !positionAttributes || !normalAttributes || !uvAttributes) {

return;
}
const vertexCount = positionAttributes.length / 3;

const tangentBuffer = new Float32Array(vertexCount * 4);
this.setVerticesData(VertexBuffer.TangentKind, tangentBuffer);

const tan1: Vector3[] = [];
const tan2: Vector3[] = [];

for (let i = 0; i < vertexCount; i++) {
tan1[i] = new Vector3();
tan2[i] = new Vector3();
}

const vA = new Vector3();
const vB = new Vector3();
const vC = new Vector3();

const uvA = new Vector2();
const uvB = new Vector2();
const uvC = new Vector2();

const sdir = new Vector3();
const tdir = new Vector3();

function handleTriangle(a: number, b: number, c: number) {
vA.fromArray(positionAttributes!, a * 3);
vB.fromArray(positionAttributes!, b * 3);
vC.fromArray(positionAttributes!, c * 3);

uvA.fromArray(uvAttributes!, a * 2);
uvB.fromArray(uvAttributes!, b * 2);
uvC.fromArray(uvAttributes!, c * 2);

vB.subtractToRef(vA, sdir);
vC.subtractToRef(vA, tdir);

uvB.subtractToRef(uvA, uvB);
uvC.subtractToRef(uvA, uvC);

const r = 1.0 / (uvB.x * uvC.y - uvC.x * uvB.y);

// silently ignore degenerate uv triangles having coincident or colinear vertices

if (!isFinite(r)) return;

}

let groups = this._groups;

if (groups.length === 0) {
groups = [
{
start: 0,
count: index.length,
},
];
}

for (let i = 0, il = groups.length; i < il; ++i) {
const group = groups[i];

const start = group.start;
const count = group.count;

for (let j = start, jl = start + count; j < jl; j += 3) {
handleTriangle(index[j + 0], index[j + 1], index[j + 2]);
}
}

const tmp = new Vector3();
const tmp2 = new Vector3();
const n = new Vector3();
const n2 = new Vector3();

function handleVertex(v: number) {
n.fromArray(normalAttributes!, v);
n2.copyFrom(n);

const t = tan1[v];

// Gram-Schmidt orthogonalize

tmp.copyFrom(t);
const dot = n.dot(t);
tmp.subtractInPlace(n.multiplyByFloats(dot, dot, dot)).normalize();

// Calculate handedness

tmp2.copyFrom(n2.cross(t));

const test = tmp2.dot(tan2[v]);
const w = test < 0.0 ? -1.0 : 1.0;

tangentBuffer[v * 4] = tmp.x;
tangentBuffer[v * 4 + 1] = tmp.y;
tangentBuffer[v * 4 + 2] = tmp.z;
tangentBuffer[v * 4 + 3] = w;
}

for (let i = 0, il = groups.length; i < il; ++i) {
const group = groups[i];

const start = group.start;
const count = group.count;

for (let j = start, jl = start + count; j < jl; j += 3) {
handleVertex(index[j + 0]);
handleVertex(index[j + 1]);
handleVertex(index[j + 2]);
}
}
}
``````

Just cross the normal and up vector should get the tangent I think.

2 Likes