@loaders.gl/math
Version:
Experimental math classes for loaders.gl
62 lines (50 loc) • 1.98 kB
text/typescript
import type {TypedArray} from '@math.gl/core';
import {Vector3} from '@math.gl/core';
import {GL} from '../constants';
import {assert} from '../utils/assert';
import {makePrimitiveIterator} from '../iterators/primitive-iterator';
import {getPrimitiveModeType} from '../primitives/modes';
import {getPositions} from './get-attribute-from-geometry';
type Geometry = {
mode: any;
indices?: {size: number; values: TypedArray};
attributes?: {};
};
/**
* Computes vertex normals for a geometry
* @param param0
* @returns
*/
// eslint-disable-next-line max-statements
export function computeVertexNormals(geometry: Geometry): Float32Array {
// Only support GL.TRIANGLES, GL.TRIANGLE_STRIP, GL.TRIANGLE_FAN
assert(getPrimitiveModeType(geometry.mode) === GL.TRIANGLES, 'TRIANGLES required');
const {values: positions} = getPositions(geometry);
const normals = new Float32Array(positions.length);
const vectorA = new Vector3();
const vectorB = new Vector3();
const vectorC = new Vector3();
const vectorCB = new Vector3();
const vectorAB = new Vector3();
for (const primitive of makePrimitiveIterator(geometry)) {
vectorA.fromArray(positions, primitive.i1 * 3);
vectorB.fromArray(positions, primitive.i2 * 3 + 3);
vectorC.fromArray(positions, primitive.i3 * 3 + 6);
vectorCB.subVectors(vectorC, vectorB);
vectorAB.subVectors(vectorA, vectorB);
const normal = vectorCB.cross(vectorAB);
normal.normalize();
// @ts-ignore
const {primitiveIndex} = primitive;
normals[primitiveIndex * 9 + 0] = normal.x;
normals[primitiveIndex * 9 + 1] = normal.y;
normals[primitiveIndex * 9 + 2] = normal.z;
normals[primitiveIndex * 9 + 3] = normal.x;
normals[primitiveIndex * 9 + 4] = normal.y;
normals[primitiveIndex * 9 + 5] = normal.z;
normals[primitiveIndex * 9 + 6] = normal.x;
normals[primitiveIndex * 9 + 7] = normal.y;
normals[primitiveIndex * 9 + 8] = normal.z;
}
return normals;
}