Files
Webklar.com/node_modules/ogl/src/extras/helpers/FaceNormalsHelper.js
Basilosaurusrex f027651f9b main repo
2025-11-24 18:09:40 +01:00

105 lines
3.3 KiB
JavaScript

import { Mesh } from '../../core/Mesh.js';
import { Program } from '../../core/Program.js';
import { Geometry } from '../../core/Geometry.js';
import { Vec3 } from '../../math/Vec3.js';
import { Mat3 } from '../../math/Mat3.js';
const vA = /* @__PURE__ */ new Vec3();
const vB = /* @__PURE__ */ new Vec3();
const vC = /* @__PURE__ */ new Vec3();
const vCenter = /* @__PURE__ */ new Vec3();
const vNormal = /* @__PURE__ */ new Vec3();
export class FaceNormalsHelper extends Mesh {
constructor(object, { size = 0.1, color = new Vec3(0.15, 0.86, 0.86), ...meshProps } = {}) {
const gl = object.gl;
const positionData = object.geometry.attributes.position.data;
const sizeData = new Float32Array([0, size]);
const indexAttr = object.geometry.attributes.index;
const getIndex = indexAttr ? (i) => indexAttr.data[i] : (i) => i;
const numVertices = indexAttr ? indexAttr.data.length : Math.floor(positionData.length / 3);
const nNormals = Math.floor(numVertices / 3);
const positionsArray = new Float32Array(nNormals * 2 * 3);
const normalsArray = new Float32Array(nNormals * 2 * 3);
const sizeArray = new Float32Array(nNormals * 2);
for (let i = 0; i < numVertices; i += 3) {
vA.fromArray(positionData, getIndex(i + 0) * 3);
vB.fromArray(positionData, getIndex(i + 1) * 3);
vC.fromArray(positionData, getIndex(i + 2) * 3);
vCenter
.add(vA, vB)
.add(vC)
.multiply(1 / 3);
vA.sub(vA, vB);
vC.sub(vC, vB);
vNormal.cross(vC, vA).normalize();
// duplicate position and normal for line start and end point
const i2 = i * 2;
positionsArray.set(vCenter, i2);
positionsArray.set(vCenter, i2 + 3);
normalsArray.set(vNormal, i2);
normalsArray.set(vNormal, i2 + 3);
sizeArray.set(sizeData, (i / 3) * 2);
}
const geometry = new Geometry(gl, {
position: { size: 3, data: positionsArray },
normal: { size: 3, data: normalsArray },
size: { size: 1, data: sizeArray },
});
const program = new Program(gl, {
vertex,
fragment,
uniforms: {
color: { value: color },
worldNormalMatrix: { value: new Mat3() },
objectWorldMatrix: { value: object.worldMatrix },
},
});
super(gl, { ...meshProps, mode: gl.LINES, geometry, program });
this.object = object;
}
draw(arg) {
this.program.uniforms.worldNormalMatrix.value.getNormalMatrix(this.object.worldMatrix);
super.draw(arg);
}
}
const vertex = /* glsl */ `
attribute vec3 position;
attribute vec3 normal;
attribute float size;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
uniform mat4 objectWorldMatrix;
uniform mat3 worldNormalMatrix;
void main() {
vec3 n = normalize(worldNormalMatrix * normal) * size;
vec3 p = (objectWorldMatrix * vec4(position, 1.0)).xyz;
gl_Position = projectionMatrix * viewMatrix * vec4(p + n, 1.0);
}
`;
const fragment = /* glsl */ `
precision highp float;
uniform vec3 color;
void main() {
gl_FragColor = vec4(color, 1.0);
}
`;