playcanvas
Version:
PlayCanvas WebGL game engine
131 lines (128 loc) • 4.5 kB
JavaScript
import { Vec2 } from '../../core/math/vec2.js';
import { Vec3 } from '../../core/math/vec3.js';
const calculateNormals = (positions, indices)=>{
const triangleCount = indices.length / 3;
const vertexCount = positions.length / 3;
const p1 = new Vec3();
const p2 = new Vec3();
const p3 = new Vec3();
const p1p2 = new Vec3();
const p1p3 = new Vec3();
const faceNormal = new Vec3();
const normals = [];
for(let i = 0; i < positions.length; i++){
normals[i] = 0;
}
for(let i = 0; i < triangleCount; i++){
const i1 = indices[i * 3];
const i2 = indices[i * 3 + 1];
const i3 = indices[i * 3 + 2];
p1.set(positions[i1 * 3], positions[i1 * 3 + 1], positions[i1 * 3 + 2]);
p2.set(positions[i2 * 3], positions[i2 * 3 + 1], positions[i2 * 3 + 2]);
p3.set(positions[i3 * 3], positions[i3 * 3 + 1], positions[i3 * 3 + 2]);
p1p2.sub2(p2, p1);
p1p3.sub2(p3, p1);
faceNormal.cross(p1p2, p1p3).normalize();
normals[i1 * 3] += faceNormal.x;
normals[i1 * 3 + 1] += faceNormal.y;
normals[i1 * 3 + 2] += faceNormal.z;
normals[i2 * 3] += faceNormal.x;
normals[i2 * 3 + 1] += faceNormal.y;
normals[i2 * 3 + 2] += faceNormal.z;
normals[i3 * 3] += faceNormal.x;
normals[i3 * 3 + 1] += faceNormal.y;
normals[i3 * 3 + 2] += faceNormal.z;
}
for(let i = 0; i < vertexCount; i++){
const nx = normals[i * 3];
const ny = normals[i * 3 + 1];
const nz = normals[i * 3 + 2];
const invLen = 1 / Math.sqrt(nx * nx + ny * ny + nz * nz);
normals[i * 3] *= invLen;
normals[i * 3 + 1] *= invLen;
normals[i * 3 + 2] *= invLen;
}
return normals;
};
const calculateTangents = (positions, normals, uvs, indices)=>{
const triangleCount = indices.length / 3;
const vertexCount = positions.length / 3;
const v1 = new Vec3();
const v2 = new Vec3();
const v3 = new Vec3();
const w1 = new Vec2();
const w2 = new Vec2();
const w3 = new Vec2();
const sdir = new Vec3();
const tdir = new Vec3();
const tan1 = new Float32Array(vertexCount * 3);
const tan2 = new Float32Array(vertexCount * 3);
const tangents = [];
for(let i = 0; i < triangleCount; i++){
const i1 = indices[i * 3];
const i2 = indices[i * 3 + 1];
const i3 = indices[i * 3 + 2];
v1.set(positions[i1 * 3], positions[i1 * 3 + 1], positions[i1 * 3 + 2]);
v2.set(positions[i2 * 3], positions[i2 * 3 + 1], positions[i2 * 3 + 2]);
v3.set(positions[i3 * 3], positions[i3 * 3 + 1], positions[i3 * 3 + 2]);
w1.set(uvs[i1 * 2], uvs[i1 * 2 + 1]);
w2.set(uvs[i2 * 2], uvs[i2 * 2 + 1]);
w3.set(uvs[i3 * 2], uvs[i3 * 2 + 1]);
const x1 = v2.x - v1.x;
const x2 = v3.x - v1.x;
const y1 = v2.y - v1.y;
const y2 = v3.y - v1.y;
const z1 = v2.z - v1.z;
const z2 = v3.z - v1.z;
const s1 = w2.x - w1.x;
const s2 = w3.x - w1.x;
const t1 = w2.y - w1.y;
const t2 = w3.y - w1.y;
const area = s1 * t2 - s2 * t1;
if (area === 0) {
sdir.set(0, 1, 0);
tdir.set(1, 0, 0);
} else {
const r = 1 / area;
sdir.set((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r);
tdir.set((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r);
}
tan1[i1 * 3 + 0] += sdir.x;
tan1[i1 * 3 + 1] += sdir.y;
tan1[i1 * 3 + 2] += sdir.z;
tan1[i2 * 3 + 0] += sdir.x;
tan1[i2 * 3 + 1] += sdir.y;
tan1[i2 * 3 + 2] += sdir.z;
tan1[i3 * 3 + 0] += sdir.x;
tan1[i3 * 3 + 1] += sdir.y;
tan1[i3 * 3 + 2] += sdir.z;
tan2[i1 * 3 + 0] += tdir.x;
tan2[i1 * 3 + 1] += tdir.y;
tan2[i1 * 3 + 2] += tdir.z;
tan2[i2 * 3 + 0] += tdir.x;
tan2[i2 * 3 + 1] += tdir.y;
tan2[i2 * 3 + 2] += tdir.z;
tan2[i3 * 3 + 0] += tdir.x;
tan2[i3 * 3 + 1] += tdir.y;
tan2[i3 * 3 + 2] += tdir.z;
}
const t1 = new Vec3();
const t2 = new Vec3();
const n = new Vec3();
const temp = new Vec3();
for(let i = 0; i < vertexCount; i++){
n.set(normals[i * 3], normals[i * 3 + 1], normals[i * 3 + 2]);
t1.set(tan1[i * 3], tan1[i * 3 + 1], tan1[i * 3 + 2]);
t2.set(tan2[i * 3], tan2[i * 3 + 1], tan2[i * 3 + 2]);
const ndott = n.dot(t1);
temp.copy(n).mulScalar(ndott);
temp.sub2(t1, temp).normalize();
tangents[i * 4] = temp.x;
tangents[i * 4 + 1] = temp.y;
tangents[i * 4 + 2] = temp.z;
temp.cross(n, t1);
tangents[i * 4 + 3] = temp.dot(t2) < 0.0 ? -1 : 1.0;
}
return tangents;
};
export { calculateNormals, calculateTangents };