diff --git a/resources/static/normal.svg b/resources/static/normal.svg new file mode 100644 index 0000000..d4ffa5a --- /dev/null +++ b/resources/static/normal.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/event.ts b/src/event.ts index c13f69d..bf8c1d9 100644 --- a/src/event.ts +++ b/src/event.ts @@ -6,6 +6,7 @@ export enum EAppEvent { onModelAvailableChanged, onGridEnabledChanged, onWireframeEnabledChanged, + onNormalsEnabledChanged, } /* eslint-enable */ diff --git a/src/geometry.ts b/src/geometry.ts index 151067e..301448e 100644 --- a/src/geometry.ts +++ b/src/geometry.ts @@ -1,5 +1,5 @@ import * as twgl from 'twgl.js'; -import { UVTriangle } from './triangle'; +import { Triangle, UVTriangle } from './triangle'; import { Vector3 } from './vector'; import { AttributeData, RenderBuffer } from './buffer'; import { Bounds, RGB } from './util'; @@ -318,6 +318,30 @@ export class DebugGeometryTemplates { return buffer; } + public static meshNormals(mesh: Mesh, colour: RGB): RenderBuffer { + const buffer = new RenderBuffer([ + { name: 'position', numComponents: 3 }, + { name: 'colour', numComponents: 3 }, + ]); + + for (let triIndex = 0; triIndex < mesh.getTriangleCount(); ++triIndex) { + const normalLength = 0.1; + const vertices = mesh.getVertices(triIndex); + const normals = mesh.getNormals(triIndex); + const avgNormal = Vector3.add(normals.v0, normals.v1).add(normals.v2).divScalar(3.0); + const tri = new Triangle(vertices.v0, vertices.v1, vertices.v2); + const start = tri.getCentre(); + const end = Vector3.add(start, Vector3.mulScalar(avgNormal, normalLength)); + buffer.add(DebugGeometryTemplates.line( + start, + end, + colour, + )); + } + + return buffer; + } + static _generateCirclePoints(centre: Vector3, normal: Vector3, radius: number, steps: number): Vector3[] { normal = normal.copy().normalise(); diff --git a/src/renderer.ts b/src/renderer.ts index 675a18c..a10c6e0 100644 --- a/src/renderer.ts +++ b/src/renderer.ts @@ -25,6 +25,7 @@ export enum MeshType { enum EDebugBufferComponents { Grid, Wireframe, + Normals, Bounds, } /* eslint-enable */ @@ -117,6 +118,12 @@ export class Renderer { EventManager.Get.broadcast(EAppEvent.onWireframeEnabledChanged, isEnabled); } + public toggleIsNormalsEnabled() { + const isEnabled = !this._isGridComponentEnabled[EDebugBufferComponents.Normals]; + this._isGridComponentEnabled[EDebugBufferComponents.Normals] = isEnabled; + EventManager.Get.broadcast(EAppEvent.onNormalsEnabledChanged, isEnabled); + } + public useMesh(mesh: Mesh) { EventManager.Get.broadcast(EAppEvent.onModelAvailableChanged, MeshType.TriangleMesh, false); EventManager.Get.broadcast(EAppEvent.onModelAvailableChanged, MeshType.VoxelMesh, false); @@ -164,6 +171,7 @@ export class Renderer { this._debugBuffers[MeshType.TriangleMesh][EDebugBufferComponents.Grid] = DebugGeometryTemplates.grid(true, true, 0.25); this._debugBuffers[MeshType.TriangleMesh][EDebugBufferComponents.Wireframe] = DebugGeometryTemplates.meshWireframe(mesh, new RGB(0.18, 0.52, 0.89)); + this._debugBuffers[MeshType.TriangleMesh][EDebugBufferComponents.Normals] = DebugGeometryTemplates.meshNormals(mesh, new RGB(0.89, 0.52, 0.18)); this._modelsAvailable = 1; this.setModelToUse(MeshType.TriangleMesh); @@ -220,7 +228,7 @@ export class Renderer { // ///////////////////////////////////////////////////////////////////////// private _drawDebug() { - const debugComponents = [EDebugBufferComponents.Grid, EDebugBufferComponents.Wireframe]; + const debugComponents = [EDebugBufferComponents.Grid, EDebugBufferComponents.Wireframe, EDebugBufferComponents.Normals]; for (const debugComp of debugComponents) { if (this._isGridComponentEnabled[debugComp]) { ASSERT(this._debugBuffers[this._meshToUse]); diff --git a/src/ui/layout.ts b/src/ui/layout.ts index ee1f922..c52e1d5 100644 --- a/src/ui/layout.ts +++ b/src/ui/layout.ts @@ -195,12 +195,21 @@ export class UI { const modelUsed = args[0][0][0] as MeshType; return modelUsed === MeshType.TriangleMesh; }), + 'normals': new ToolbarItemElement('normal', () => { + Renderer.Get.toggleIsNormalsEnabled(); + }, EAppEvent.onNormalsEnabledChanged, (...args: any[]) => { + const isEnabled = args[0][0][0] as boolean; + return isEnabled; + }, EAppEvent.onModelActiveChanged, (...args: any[]) => { + const modelUsed = args[0][0][0] as MeshType; + return modelUsed === MeshType.TriangleMesh; + }), /* 'bounds': new ToolbarItemElement('bounds', () => { }), */ }, - elementsOrder: ['grid', 'wireframe'], // ['grid', 'bounds'], + elementsOrder: ['grid', 'wireframe', 'normals'], // ['grid', 'bounds'], }, }, groupsOrder: ['viewmode', 'zoom', 'debug'],