From 7a509b654c0c054e852b3614ced7fc71c6853d43 Mon Sep 17 00:00:00 2001 From: Szymon Nowakowski Date: Wed, 16 Aug 2023 21:42:38 +0200 Subject: [PATCH] Quaternion and angle helpers, updated example --- example/script.ts | 24 +++++++++++---------- src/data/Quaternion.ts | 48 ++++++++++++++++++++++++++++++++++++++++++ src/geometry.ts | 7 ++++++ src/oktaeder.ts | 1 + 4 files changed, 69 insertions(+), 11 deletions(-) create mode 100644 src/geometry.ts diff --git a/example/script.ts b/example/script.ts index 9f39509..b1fd372 100644 --- a/example/script.ts +++ b/example/script.ts @@ -1,5 +1,5 @@ -import { Color, Material, Mesh, Node, PerspectiveCamera, PointLight, Quaternion, Scene, Submesh, Vector3 } from "../src/data/index"; -import { Renderer } from "../src/oktaeder"; +import { Color, DirectionalLight, Material, Mesh, Node, PerspectiveCamera, PointLight, Quaternion, Scene, Submesh, Vector3 } from "../src/data/index"; +import { Renderer, degToRad } from "../src/oktaeder"; import "./style.css"; new EventSource("/esbuild").addEventListener("change", () => location.reload()); @@ -11,7 +11,7 @@ onResize.call(window); const renderer = await Renderer.init(canvas); const camera = new PerspectiveCamera({ - verticalFovRad: 50 * (Math.PI / 180), + verticalFovRad: degToRad(50), nearPlane: 0.001, farPlane: Infinity, }); @@ -47,12 +47,11 @@ const mesh = new Mesh({ vertexBuffer, indexBuffer, submeshes: [submesh] }); const material = new Material({ baseColor: Color.white(), roughness: 0.5, - metallic: 0, + metallic: 1, }); const node = new Node({ mesh, materials: [material] }); -const cameraPitchRad = 15 * (Math.PI / 180); const scene = new Scene({ nodes: [ node, @@ -72,9 +71,13 @@ const scene = new Scene({ translation: new Vector3(0, 1, 1), light: new PointLight({ color: new Color(1, 1, 0) }), }), + new Node({ + rotation: Quaternion.fromRotationYZ(degToRad(-90)), + light: new DirectionalLight({ color: new Color(0.5, 0.5, 0.5) }), + }), new Node({ translation: new Vector3(0, 0.8, -3), - rotation: new Quaternion(Math.sin(0.5 * cameraPitchRad), 0, 0, Math.cos(0.5 * cameraPitchRad)), + rotation: Quaternion.fromRotationYZ(degToRad(15)), camera, }), ], @@ -86,12 +89,11 @@ function onResize(this: Window) { canvas.height = this.innerHeight; } -const rotation = Quaternion.identity(); +const _quaternion = Quaternion.identity(); -function draw(time: number) { - rotation.y = Math.cos(0.001 * time); - rotation.w = Math.sin(0.001 * time); - node.setRotation(rotation); +function draw(timeMs: number) { + const time = 0.001 * timeMs; + node.setRotation(_quaternion.setRotationZX(-0.5 * time)); renderer.render(scene, camera); requestAnimationFrame(draw); diff --git a/src/data/Quaternion.ts b/src/data/Quaternion.ts index 6105f00..8a8d928 100644 --- a/src/data/Quaternion.ts +++ b/src/data/Quaternion.ts @@ -41,6 +41,27 @@ export class Quaternion { return new Quaternion(0, 0, 0, 1); } + static fromRotationXY(angleRad: number): Quaternion { + const halfAngleRad = 0.5 * angleRad; + const c = Math.cos(halfAngleRad); + const s = Math.sin(halfAngleRad); + return new Quaternion(0, 0, s, c); + } + + static fromRotationYZ(angleRad: number): Quaternion { + const halfAngleRad = 0.5 * angleRad; + const c = Math.cos(halfAngleRad); + const s = Math.sin(halfAngleRad); + return new Quaternion(s, 0, 0, c); + } + + static fromRotationZX(angleRad: number): Quaternion { + const halfAngleRad = 0.5 * angleRad; + const c = Math.cos(halfAngleRad); + const s = Math.sin(halfAngleRad); + return new Quaternion(0, s, 0, c); + } + setObject(object: QuaternionObject): Quaternion { this.x = object.x; this.y = object.y; @@ -64,6 +85,33 @@ export class Quaternion { this.w = 1; return this; } + + setRotationXY(angleRad: number): Quaternion { + const halfAngleRad = 0.5 * angleRad; + this.x = 0; + this.y = 0; + this.z = Math.sin(halfAngleRad); + this.w = Math.cos(halfAngleRad); + return this; + } + + setRotationYZ(angleRad: number): Quaternion { + const halfAngleRad = 0.5 * angleRad; + this.x = Math.sin(halfAngleRad); + this.y = 0; + this.z = 0; + this.w = Math.cos(halfAngleRad); + return this; + } + + setRotationZX(angleRad: number): Quaternion { + const halfAngleRad = 0.5 * angleRad; + this.x = 0; + this.y = Math.sin(halfAngleRad); + this.z = 0; + this.w = Math.cos(halfAngleRad); + return this; + } } Object.defineProperty(Quaternion.prototype, "type", { value: "Quaternion" }); diff --git a/src/geometry.ts b/src/geometry.ts new file mode 100644 index 0000000..8bc6ef8 --- /dev/null +++ b/src/geometry.ts @@ -0,0 +1,7 @@ +export function degToRad(angleDeg: number): number { + return angleDeg * Math.PI / 180; +} + +export function radToDeg(angleRad: number): number { + return angleRad * 180 / Math.PI; +} diff --git a/src/oktaeder.ts b/src/oktaeder.ts index cf4f721..3899453 100644 --- a/src/oktaeder.ts +++ b/src/oktaeder.ts @@ -5,6 +5,7 @@ */ export * from "./_BinaryWriter"; +export * from "./geometry"; export * from "./shader"; import { _BinaryWriter as BinaryWriter } from "./_BinaryWriter";