From d69561455d15812ec1e9b7d8af0c0b649d9e4c67 Mon Sep 17 00:00:00 2001 From: Tom Greenwood Date: Mon, 5 Jan 2026 13:16:58 +0000 Subject: [PATCH 01/10] improve maths lib types --- demo-01-ts-webgl/index.ts | 56 +++++---- demo-01-ts-webgl/lib/BasicRenderProgram.ts | 25 ++-- demo-01-ts-webgl/lib/events.ts | 2 +- demo-01-ts-webgl/lib/light.ts | 10 +- demo-01-ts-webgl/lib/mat4.ts | 126 +++++++++++++++++---- demo-01-ts-webgl/lib/mesh.ts | 6 +- demo-01-ts-webgl/lib/raycast.ts | 25 ++-- demo-01-ts-webgl/lib/scene.ts | 3 +- demo-01-ts-webgl/lib/vec.ts | 75 +++++++++--- ts-tests/raycastScene.test.ts | 50 ++++---- ts-tests/raycastTriangle.test.ts | 61 ++++++---- ts-tests/raycastVertices.test.ts | 16 +-- ts-tests/scene.test.ts | 8 +- 13 files changed, 302 insertions(+), 161 deletions(-) diff --git a/demo-01-ts-webgl/index.ts b/demo-01-ts-webgl/index.ts index a9b159a..87ff742 100644 --- a/demo-01-ts-webgl/index.ts +++ b/demo-01-ts-webgl/index.ts @@ -10,16 +10,16 @@ import { m4fromPositionAndEuler, m4lookAt, m4vectorMultiply, m4yRotation } from import { initGlState } from './lib/gl' import { getWorldRayFromClipSpaceAndCamera, rayIntersectsScene, sortBySceneDepth } from './lib/raycast' import { getPointerClickInClipSpace } from './lib/events' -import { Vec3, Vec4, calculateOrbitPosition } from './lib/vec' +import { Color, POS_ORIGIN, ROT_NONE, Vec3, Vec4, calculateOrbitPosition } from './lib/vec' type NodeName = "yellow tree" | "orange tree" | "green tree" | "floor"; -const meshColorMap: Record = { - "yellow tree": [0.7, 0.7, 0.01 ], - "orange tree": [0.6, 0.3, 0.001], - "green tree": [0.1, 0.6, 0.1], - "floor": [0.2, 0.2, 0.4] +const meshColorMap: Record = { + "yellow tree": { r: 0.7, g: 0.7, b: 0.01 }, + "orange tree": { r: 0.6, g: 0.3, b: 0.001 }, + "green tree": { r: 0.1, g: 0.6, b: 0.1 }, + "floor": { r: 0.2, g: 0.2, b: 0.4} }; type Orbit = { @@ -33,7 +33,7 @@ const orbit: Orbit = { azimuth: Math.PI * -0.2, // horizontal angle, in radians elevation: 3 * Math.PI / 4, // vertical angle, in radians radius: 15, - target: [-3, 2, -2], + target: {x: -3, y: 2, z: -2}, sensitivity: 0.01, } @@ -78,35 +78,35 @@ if (!basicRenderProgram) { const vertices = await loadObj('/rainbowtree.obj'); -const yellowTree = initSceneNode(m4fromPositionAndEuler( [0,0,0], [0, Math.PI /2, 0]), +const yellowTree = initSceneNode(m4fromPositionAndEuler( POS_ORIGIN, { x: 0, y: Math.PI /2, z: 0}), { vertices, material: { color: meshColorMap["yellow tree"], - specularColor: [0.2,0.2,0.2], + specularColor: { r: 0.2, g: 0.2, b:0.2 }, shininess: 0.9 }}, "yellow tree") const orangeTree = initSceneNode( - m4fromPositionAndEuler( [5,0,0], [0, Math.PI /2, 0]), + m4fromPositionAndEuler( { x: 5, y: 0, z: 0 }, { x: 0, y: Math.PI /2, z: 0 }), { vertices, material: { color: meshColorMap["orange tree"], - specularColor: [0.2,0.2,0.2], + specularColor: { r: 0.2, g: 0.2, b: 0.2}, shininess: 0.9 }}, "orange tree") const greenTree = initSceneNode( - m4fromPositionAndEuler( [5,0,0], [0, Math.PI /2, 0]), + m4fromPositionAndEuler( { x: 5, y: 0, z: 0}, { x: 0, y: Math.PI /2, z: 0 }), { vertices, material: { color: meshColorMap["green tree"], - specularColor: [0.2,0.2,0.2], + specularColor: { r: 0.2, g: 0.2, b: 0.2}, shininess: 0.5 }}, "green tree") @@ -145,12 +145,12 @@ const floorVertices: Vertices = { } -const floorNode = initSceneNode(m4fromPositionAndEuler( [0,0.1,0], [0, 0, 0]), +const floorNode = initSceneNode(m4fromPositionAndEuler( { x: 0, y: 0.1, z: 0}, ROT_NONE), { vertices: floorVertices, material: { color: meshColorMap["floor"], - specularColor: [0.2,0.2,0.2], + specularColor: { r: 0.2, g: 0.2, b: 0.2}, shininess: 0.9 }}, "floor") @@ -161,17 +161,17 @@ const scene = [yellowTree, floorNode] // create lights const ambientLight: AmbientLight = { - color: [0.2, 0.2, 0.2] + color: { r: 0.2, g: 0.2, b: 0.2 } }; const directionalLight: DirectionalLight = { - rotation : [ 0.0, -0.8 , -0.5], - color : [0.6, 0.6, 0.6], + rotation : { x: 0, y: -0.8 , z: -0.5}, + color : { r: 0.6, g: 0.6, b: 0.6 }, }; const pointLight: PointLight = { - position: [ 0, 5.0, 5], - color: [ 0.7, 0.7, 0.7], + position: { x: 0, y: 5.0, z: 5 }, + color: {r: 0.7, g: 0.7, b: 0.7 }, constant: 1.0, linear: 0.009, quadratic: 0.032 @@ -184,7 +184,7 @@ const cameraPosition = calculateOrbitPosition( orbit.radius ); -const up: Vec3 = [0, 1, 0] +const up: Vec3 = {x: 0, y: 1, z: 0 } const camera: Camera = { fieldOfViewRadians: degToRad(60), aspect: canvas.clientWidth / canvas.clientHeight, @@ -197,7 +197,7 @@ const camera: Camera = { const input: InputState = { - pointerPosition: [0,0] + pointerPosition: {x: 0, y: 0 } } @@ -313,13 +313,11 @@ function resizeCanvasToDisplaySize(canvas: HTMLCanvasElement): void { function updateLight(pointLight: PointLight, dt: number) { const rotator = m4yRotation(Math.PI / (dt * 10000)); - const oldTransform: Vec4 = [ - pointLight.position[0], - pointLight.position[1], - pointLight.position[2], - 0.0 - ]; + const oldTransform: Vec4 = { + ...pointLight.position, + w: 0.0 + }; const newTransform = m4vectorMultiply(oldTransform, rotator); - pointLight.position = [newTransform[0],newTransform[1],newTransform[2]] + pointLight.position = { x: newTransform.x, y: newTransform.y, z: newTransform.z } } \ No newline at end of file diff --git a/demo-01-ts-webgl/lib/BasicRenderProgram.ts b/demo-01-ts-webgl/lib/BasicRenderProgram.ts index 49e5f64..cc28248 100644 --- a/demo-01-ts-webgl/lib/BasicRenderProgram.ts +++ b/demo-01-ts-webgl/lib/BasicRenderProgram.ts @@ -14,7 +14,7 @@ import shadowFragmentSource from "./shaders/depth-only.frag?raw" import { GlState } from "./gl"; import { Mesh } from "./mesh"; import { SceneNode } from "./scene"; -import { Vec3 } from "./vec"; +import { colorToArray, eulerToArray, Vec3, vec3ToArray } from "./vec"; function guaranteeUniformLocation( gl: WebGL2RenderingContext, @@ -108,17 +108,17 @@ export function updateUniforms( gl.uniformMatrix4fv(renderProgram.projectionUniformLocation, false, projectionMatrix); // update material uniforms - gl.uniform3fv(renderProgram.materialUniform.colorLocation, mesh.material.color); - gl.uniform3fv(renderProgram.materialUniform.specularColorLocation, mesh.material.specularColor); + gl.uniform3fv(renderProgram.materialUniform.colorLocation, colorToArray(mesh.material.color)); + gl.uniform3fv(renderProgram.materialUniform.specularColorLocation, colorToArray(mesh.material.specularColor)); gl.uniform1f(renderProgram.materialUniform.shininessLocation, mesh.material.shininess); // update light uniforms // set ambient light - gl.uniform3fv(renderProgram.ambientLightUniform.colorLocation,ambientLight.color); + gl.uniform3fv(renderProgram.ambientLightUniform.colorLocation, colorToArray(ambientLight.color)); // set directional light - gl.uniform3fv(renderProgram.directionalLightUniform.colorLocation,directionalLight.color); - gl.uniform3fv(renderProgram.directionalLightUniform.rotationLocation,directionalLight.rotation); + gl.uniform3fv(renderProgram.directionalLightUniform.colorLocation,colorToArray(directionalLight.color)); + gl.uniform3fv(renderProgram.directionalLightUniform.rotationLocation, eulerToArray(directionalLight.rotation)); // shadows // shadow map must be bound @@ -126,8 +126,8 @@ export function updateUniforms( // set point light - gl.uniform3fv(renderProgram.pointLightUniform.colorLocation,pointLight.color); - gl.uniform3fv(renderProgram.pointLightUniform.positionLocation,pointLight.position); + gl.uniform3fv(renderProgram.pointLightUniform.colorLocation, colorToArray(pointLight.color)); + gl.uniform3fv(renderProgram.pointLightUniform.positionLocation, vec3ToArray(pointLight.position)); gl.uniform1f(renderProgram.pointLightUniform.constantLocation,pointLight.constant); gl.uniform1f(renderProgram.pointLightUniform.linearLocation,pointLight.linear); gl.uniform1f(renderProgram.pointLightUniform.quadraticLocation,pointLight.quadratic); @@ -439,13 +439,15 @@ export function drawScene( // Compute light's view-projection matrix (for directional light) - const [x,y,z] = directionalLight.rotation + const x = directionalLight.rotation.x + const y = directionalLight.rotation.y + const z = directionalLight.rotation.z const xMatrix = m4xRotation(x) const yMatrix = m4xRotation(y) const zMatrix = m4xRotation(z) - const imaginaryCameraPosition: Vec3 = [10,10,10] + const imaginaryCameraPosition: Vec3 = { x: 10,y: 10, z: 10} let effectiveCameraPosition = m4PositionMultiply(imaginaryCameraPosition,xMatrix) effectiveCameraPosition = m4PositionMultiply(effectiveCameraPosition,yMatrix) effectiveCameraPosition = m4PositionMultiply(effectiveCameraPosition,zMatrix) @@ -608,4 +610,5 @@ export function drawShadowScene( node.children.forEach(child => drawShadowScene(glState, [child], renderProgram, shadowProgram, lightViewProj)); } }); -} \ No newline at end of file +} + diff --git a/demo-01-ts-webgl/lib/events.ts b/demo-01-ts-webgl/lib/events.ts index d9efedf..c022273 100644 --- a/demo-01-ts-webgl/lib/events.ts +++ b/demo-01-ts-webgl/lib/events.ts @@ -17,5 +17,5 @@ export function getPointerClickInClipSpace( x = x / canvas.width * 2 -1; y = y / canvas.height * -2 + 1; - return [x,y] + return {x,y} } \ No newline at end of file diff --git a/demo-01-ts-webgl/lib/light.ts b/demo-01-ts-webgl/lib/light.ts index 5caa378..81ed04f 100644 --- a/demo-01-ts-webgl/lib/light.ts +++ b/demo-01-ts-webgl/lib/light.ts @@ -1,7 +1,7 @@ -import { Vec3 } from "./vec"; +import { Color, Vec3, Euler } from "./vec"; export type PointLight = { - color: Vec3; + color: Color; position: Vec3; constant: number; linear: number; @@ -9,10 +9,10 @@ export type PointLight = { } export type DirectionalLight = { - color: Vec3; - rotation: Vec3; + color: Color; + rotation: Euler; }; export type AmbientLight = { - color: Vec3; + color: Color; } diff --git a/demo-01-ts-webgl/lib/mat4.ts b/demo-01-ts-webgl/lib/mat4.ts index 2720b5e..4f2cf43 100644 --- a/demo-01-ts-webgl/lib/mat4.ts +++ b/demo-01-ts-webgl/lib/mat4.ts @@ -1,5 +1,5 @@ import { Ray } from './raycast'; -import { Vec3, Vec4, normalize, subtractVectors, cross } from './vec' +import { Vec3, Vec4, normalize, subtractVectors, cross, QUAT_ORIGIN, vec3ToArray, vec4ToArray } from './vec' export type Mat4 = [ @@ -18,12 +18,12 @@ export function m4lookAt(cameraPosition: Vec3, target: Vec3, up: Vec3): Mat4 { const yAxis = normalize(cross(zAxis, xAxis)); return [ - xAxis[0], xAxis[1], xAxis[2], 0, - yAxis[0], yAxis[1], yAxis[2], 0, - zAxis[0], zAxis[1], zAxis[2], 0, - cameraPosition[0], - cameraPosition[1], - cameraPosition[2], + xAxis.x, xAxis.y, xAxis.z, 0, + yAxis.x, yAxis.y, yAxis.z, 0, + zAxis.x, zAxis.y, zAxis.z, 0, + cameraPosition.x, + cameraPosition.y, + cameraPosition.z, 1, ]; } @@ -315,35 +315,117 @@ export function m4inverse(m: Mat4): Mat4 { } export function m4vectorMultiply(v: Vec4, m: Mat4): Vec4 { - const dst: Vec4 = [0,0,0,0]; + const dst: [number, number, number, number] = [0,0,0,0]; + const vArray = vec4ToArray(v) for (let i = 0; i < 4; ++i) { for (let j = 0; j < 4; ++j) { - dst[i]! += v[j]! * m[j * 4 + i]!; // ts is not smart enough to see that we set dst[i] to a number already + dst[i]! += vArray[j]! * m[j * 4 + i]!; // ts is not smart enough to see that we set dst[i] to a number already } } - return dst; + return { x: dst[0], y: dst[1], z: dst[2], w: dst[3] }; + + // const m00 = m[0 * 4 + 0]!; + // const m01 = m[0 * 4 + 1]!; + // const m02 = m[0 * 4 + 2]!; + // const m03 = m[0 * 4 + 3]!; + // const m10 = m[1 * 4 + 0]!; + // const m11 = m[1 * 4 + 1]!; + // const m12 = m[1 * 4 + 2]!; + // const m13 = m[1 * 4 + 3]!; + // const m20 = m[2 * 4 + 0]!; + // const m21 = m[2 * 4 + 1]!; + // const m22 = m[2 * 4 + 2]!; + // const m23 = m[2 * 4 + 3]!; + // const m30 = m[3 * 4 + 0]!; + // const m31 = m[3 * 4 + 1]!; + // const m32 = m[3 * 4 + 2]!; + // const m33 = m[3 * 4 + 3]!; + + // return { + // x: m00 * v.x + m01 * v.y + m02 * v.z + m03 * v.w, + // y: m10 * v.x + m11 * v.y + m12 * v.z + m13 * v.w, + // z: m20 * v.x + m21 * v.y + m22 * v.z + m23 * v.w, + // w: m30 * v.x + m31 * v.y + m32 * v.z + m33 * v.w + // } } export function m4PositionMultiply(v: Vec3, m: Mat4): Vec3 { - const v1: Vec4 = [...v, 1] - const dst: Vec4 = [0,0,0,0]; + // const v1: Vec4 = {...v, w: 1} + const vArray: [number, number, number, number ] = [...vec3ToArray(v), 1] + const dst: [number, number, number, number] = [0,0,0,0]; for (let i = 0; i < 4; ++i) { for (let j = 0; j < 4; ++j) { - dst[i]! += v1[j]! * m[j * 4 + i]!; // ts is not smart enough to see that we set dst[i] to a number already + dst[i]! += vArray[j]! * m[j * 4 + i]!; // ts is not smart enough to see that we set dst[i] to a number already } } - return [dst[0]/dst[3],dst[1]/dst[3],dst[2]/dst[3]]; + + // const m00 = m[0 * 4 + 0]!; + // const m01 = m[0 * 4 + 1]!; + // const m02 = m[0 * 4 + 2]!; + // const m03 = m[0 * 4 + 3]!; + // const m10 = m[1 * 4 + 0]!; + // const m11 = m[1 * 4 + 1]!; + // const m12 = m[1 * 4 + 2]!; + // const m13 = m[1 * 4 + 3]!; + // const m20 = m[2 * 4 + 0]!; + // const m21 = m[2 * 4 + 1]!; + // const m22 = m[2 * 4 + 2]!; + // const m23 = m[2 * 4 + 3]!; + // const m30 = m[3 * 4 + 0]!; + // const m31 = m[3 * 4 + 1]!; + // const m32 = m[3 * 4 + 2]!; + // const m33 = m[3 * 4 + 3]!; + + + // const dst: Vec4 = { + // x: m00 * v1.x + m01 * v1.y + m02 * v1.z + m03 * v1.w, + // y: m10 * v1.x + m11 * v1.y + m12 * v1.z + m13 * v1.w, + // z: m20 * v1.x + m21 * v1.y + m22 * v1.z + m23 * v1.w, + // w: m30 * v1.x + m31 * v1.y + m32 * v1.z + m33 * v1.w + // } + + // return {x: dst.x/dst.w, y: dst.y/dst.w, z: dst.z/dst.w }; + return {x: dst[0]/dst[3], y: dst[1]/dst[3], z: dst[2]/dst[3] } } export function m4DirectionMultiply(v: Vec3, m: Mat4): Vec3 { - const v1: Vec4 = [...v, 0] - const dst: Vec4 = [0,0,0,0]; + + const vArray: [number, number, number, number ] = [...vec3ToArray(v), 0] + const dst: [number, number, number, number] = [0,0,0,0]; for (let i = 0; i < 4; ++i) { for (let j = 0; j < 4; ++j) { - dst[i]! += v1[j]! * m[j * 4 + i]!; // ts is not smart enough to see that we set dst[i] to a number already + dst[i]! += vArray[j]! * m[j * 4 + i]!; // ts is not smart enough to see that we set dst[i] to a number already } } - return [dst[0],dst[1],dst[2]]; + + return { x: dst[0], y: dst[1], z: dst[2] }; + + // const m00 = m[0 * 4 + 0]!; + // const m01 = m[0 * 4 + 1]!; + // const m02 = m[0 * 4 + 2]!; + // const m03 = m[0 * 4 + 3]!; + // const m10 = m[1 * 4 + 0]!; + // const m11 = m[1 * 4 + 1]!; + // const m12 = m[1 * 4 + 2]!; + // const m13 = m[1 * 4 + 3]!; + // const m20 = m[2 * 4 + 0]!; + // const m21 = m[2 * 4 + 1]!; + // const m22 = m[2 * 4 + 2]!; + // const m23 = m[2 * 4 + 3]!; + // const m30 = m[3 * 4 + 0]!; + // const m31 = m[3 * 4 + 1]!; + // const m32 = m[3 * 4 + 2]!; + // const m33 = m[3 * 4 + 3]!; + + // const v1: Vec4 = {...v, w: 0} + + // const dst: Vec4 = { + // x: m00 * v1.x + m01 * v1.y + m02 * v1.z + m03 * v1.w, + // y: m10 * v1.x + m11 * v1.y + m12 * v1.z + m13 * v1.w, + // z: m20 * v1.x + m21 * v1.y + m22 * v1.z + m23 * v1.w, + // w: m30 * v1.x + m31 * v1.y + m32 * v1.z + m33 * v1.w + // } + // return { x: dst.x, y: dst.y, z: dst.z }; } export function m4RayMultiply(ray: Ray, m: Mat4) { @@ -355,9 +437,9 @@ export function m4RayMultiply(ray: Ray, m: Mat4) { } export function m4fromPositionAndEuler(position: Vec3, euler: Vec3): Mat4 { - let mat4 = m4translate(m4yRotation(0), position[0], position[1], position[2]) ; - mat4 = m4xRotate(mat4, euler[0]); - mat4 = m4yRotate(mat4, euler[1]); - mat4 = m4zRotate(mat4, euler[2]); + let mat4 = m4translate(m4yRotation(0), position.x, position.y, position.z) ; + mat4 = m4xRotate(mat4, euler.x); + mat4 = m4yRotate(mat4, euler.y); + mat4 = m4zRotate(mat4, euler.z); return mat4; } \ No newline at end of file diff --git a/demo-01-ts-webgl/lib/mesh.ts b/demo-01-ts-webgl/lib/mesh.ts index 0bb3f7d..fb791af 100644 --- a/demo-01-ts-webgl/lib/mesh.ts +++ b/demo-01-ts-webgl/lib/mesh.ts @@ -1,5 +1,5 @@ -import { Vec3 } from "./vec"; +import { Color } from "./vec"; export type Vertices = { positions: Float32Array, @@ -9,8 +9,8 @@ export type Vertices = { } export type Material = { - color: Vec3 - specularColor: Vec3 + color: Color + specularColor: Color shininess: number } diff --git a/demo-01-ts-webgl/lib/raycast.ts b/demo-01-ts-webgl/lib/raycast.ts index 67dee8a..3c8e3ea 100644 --- a/demo-01-ts-webgl/lib/raycast.ts +++ b/demo-01-ts-webgl/lib/raycast.ts @@ -60,26 +60,18 @@ export function rayIntersectsVertices(ray: Ray, vertices: Vertices): Intersectio const intersections: Intersection[] = [] const positions = vertices.positions - - // console.log("positions", positions) - // console.log("length", positions.length) for (let i = 0; i < positions.length; i += 9) { const triangle: Triangle = [ - [positions[i]!,positions[i+1]!,positions[i+2]!], - [positions[i+3]!,positions[i+4]!,positions[i+5]!], - [positions[i+6]!,positions[i+7]!,positions[i+8]!] + {x: positions[i]!, y: positions[i+1]!,z: positions[i+2]!}, + {x: positions[i+3]!,y: positions[i+4]!,z: positions[i+5]!}, + {x: positions[i+6]!,y: positions[i+7]!,z: positions[i+8]!} ] const intersectionPoint = rayIntersectsTriangle(ray, triangle) - - // console.log("i", i) - // console.log("triangle", triangle) - // console.log("intersection", intersection) if (intersectionPoint) { - // console.log("adding intersection", intersection) intersections.push({ point: intersectionPoint, triangleIdx: i / 9}) } } @@ -109,7 +101,7 @@ export function rayIntersectsSceneNode(ray: Ray, node: SceneNode): Intersection[ while (nodeStack.length > 0) { const nodeUnderTest = nodeStack.pop()! - // console.log(nodeUnderTest) + if (nodeUnderTest.mesh) { // transform the ray into mesh space const inverseTransform = m4inverse(nodeUnderTest._worldTransform) @@ -179,9 +171,10 @@ export function getWorldRayFromClipSpaceAndCamera( clipSpacePoint: Vec2, camera: Camera) { - const [x,y] = clipSpacePoint - const nearPoint: Vec3 = [x, y, -1]; - const farPoint: Vec3 = [x, y, 1]; + const x = clipSpacePoint.x + const y = clipSpacePoint.y + const nearPoint: Vec3 = {x, y, z: -1}; + const farPoint: Vec3 = {x, y, z: 1}; const viewMatrix = m4inverse(camera.transform); const projectionMatrix = getProjectionMatrix(camera); @@ -213,7 +206,7 @@ export function sortBySceneDepth(intersections: Intersection[], camera: Camera const glPosA = m4PositionMultiply(a.point, viewProj) const glPosB = m4PositionMultiply(b.point, viewProj) - return glPosA[2] - glPosB[2] + return glPosA.z - glPosB.z }) return sorted diff --git a/demo-01-ts-webgl/lib/scene.ts b/demo-01-ts-webgl/lib/scene.ts index 86bdd56..e804d43 100644 --- a/demo-01-ts-webgl/lib/scene.ts +++ b/demo-01-ts-webgl/lib/scene.ts @@ -1,5 +1,6 @@ import { m4fromPositionAndEuler, m4multiply, Mat4 } from "./mat4"; import { Mesh } from "./mesh"; +import { POS_ORIGIN, ROT_NONE } from "./vec"; export type SceneNode = { @@ -16,7 +17,7 @@ export type Scene = SceneNode[] export function updateWorldTransform(node: SceneNode) { // n.b. this assumes the parent world transform is always up-to-date so we must keep it that way - const parentWorldTransform = node.parent?._worldTransform ?? m4fromPositionAndEuler([0,0,0], [0,0,0]); + const parentWorldTransform = node.parent?._worldTransform ?? m4fromPositionAndEuler(POS_ORIGIN, ROT_NONE); node._worldTransform = m4multiply(parentWorldTransform, node._localTransform); node.children.forEach(child => updateWorldTransform(child)) diff --git a/demo-01-ts-webgl/lib/vec.ts b/demo-01-ts-webgl/lib/vec.ts index cc846bd..8158569 100644 --- a/demo-01-ts-webgl/lib/vec.ts +++ b/demo-01-ts-webgl/lib/vec.ts @@ -1,37 +1,78 @@ -export type Vec2 = [number, number] -export type Vec3 = [number, number, number] -export type Vec4 = [number, number, number, number] +export type Vec2 = { x: number, y: number } +export type Vec3 = { x: number, y: number, z: number } +export type Vec4 = { x: number, y: number, z: number, w: number } + +export type Euler = Vec3 +export type Color = { r: number, g: number, b: number } + +export const QUAT_ORIGIN: Vec4 = { x: 0, y: 0, z: 0, w: 0 } +export const POS_ORIGIN: Vec3 = { x: 0, y: 0, z: 0 } +export const ROT_NONE: Vec3 = { x: 0, y: 0, z: 0 } + +export function colorToArray(col: Color): [number, number, number] { + return [col.r, col.g, col.b] +} + +export function eulerToArray(eul: Euler): [number, number, number] { + return [eul.x, eul.y, eul.z] +} + +export function vec3ToArray(vec: Vec3): [number, number, number] { + return [vec.x, vec.y, vec.z] +} + +export function vec4ToArray(vec: Vec4): [number, number, number, number] { + return [vec.x, vec.y, vec.z, vec.w] +} export function subtractVectors(a: Vec3, b: Vec3): Vec3 { - return [a[0] - b[0], a[1] - b[1], a[2] - b[2]]; + return { + x: a.x - b.x, + y: a.y - b.y, + z: a.z - b.z + }; } export function addVectors(a: Vec3, b: Vec3): Vec3 { - return [a[0] + b[0], a[1] + b[1], a[2] + b[2]]; + return { + x: a.x + b.x, + y: a.y + b.y, + z: a.z + b.z + }; } export function scaleVector(vec: Vec3, scalar: number): Vec3 { - return [vec[0] * scalar, vec[1] * scalar, vec[2] * scalar] + return { + x: vec.x * scalar, + y: vec.y * scalar, + z: vec.z * scalar + } } export function normalize(v: Vec3): Vec3 { - const length = Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); + const length = Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z); // make sure we don't divide by 0. if (length > 0.00001) { - return [v[0] / length, v[1] / length, v[2] / length]; + return { + x: v.x / length, + y: v.y / length, + z: v.z / length + }; } else { - return [0, 0, 0]; + return {x: 0, y: 0, z: 0}; } } export function cross(a: Vec3, b: Vec3): Vec3 { - return [a[1] * b[2] - a[2] * b[1], - a[2] * b[0] - a[0] * b[2], - a[0] * b[1] - a[1] * b[0]]; + return { + x: a.y * b.z - a.z * b.y, + y: a.z * b.x - a.x * b.z, + z: a.x * b.y - a.y * b.x + }; } export function dot(a: Vec3, b: Vec3): number { - return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; + return a.x * b.x + a.y * b.y + a.z * b.z; } export function calculateOrbitPosition( @@ -44,9 +85,9 @@ export function calculateOrbitPosition( elevation = Math.max(0.01, Math.min(Math.PI / 2 - 0.01, elevation)); // Spherical to Cartesian - const x = orbitTarget[0] + orbitRadius * Math.sin(elevation) * Math.sin(azimuth); - const y = orbitTarget[1] + orbitRadius * Math.cos(elevation); - const z = orbitTarget[2] + orbitRadius * Math.sin(elevation) * Math.cos(azimuth); + const x = orbitTarget.x + orbitRadius * Math.sin(elevation) * Math.sin(azimuth); + const y = orbitTarget.y + orbitRadius * Math.cos(elevation); + const z = orbitTarget.z + orbitRadius * Math.sin(elevation) * Math.cos(azimuth); - return [x,y,z] + return {x,y,z} } \ No newline at end of file diff --git a/ts-tests/raycastScene.test.ts b/ts-tests/raycastScene.test.ts index 8378293..0a78bff 100644 --- a/ts-tests/raycastScene.test.ts +++ b/ts-tests/raycastScene.test.ts @@ -3,6 +3,7 @@ import { Intersection, Ray, rayIntersectsSceneNode } from "demo-01-ts-webgl/lib/ import { Material, Vertices } from 'demo-01-ts-webgl/lib/mesh'; import { initSceneNode, setParent } from 'demo-01-ts-webgl/lib/scene'; import { m4fromPositionAndEuler } from 'demo-01-ts-webgl/lib/mat4'; +import { POS_ORIGIN, ROT_NONE } from 'demo-01-ts-webgl/lib/vec'; const positions = new Float32Array([ @@ -31,49 +32,49 @@ const vertices: Vertices = { } const material: Material = { - color: [1,1,1], - specularColor: [1,1,1], + color: { r: 1, g: 1, b:1}, + specularColor: {r: 1, g: 1, b: 1}, shininess: 0 } test('it correctly finds an intersection with position transform', () => { - const node = initSceneNode(m4fromPositionAndEuler([-2,0,0], [0,0,0]), { + const node = initSceneNode(m4fromPositionAndEuler({x: -2, y: 0,z: 0}, ROT_NONE), { vertices, material }) const ray: Ray = { - origin: [-11, 0.5, 0], - direction: [0, -1, 0] + origin: {x: -11, y: 0.5, z: 0}, + direction: {x: 0, y: -1, z: 0} } const result = rayIntersectsSceneNode(ray, node) - const expected: Intersection[] = [{ point: [-11, 0.0, 0], triangleIdx: 0}] + const expected: Intersection[] = [{ point: {x: -11, y: 0.0, z: 0}, triangleIdx: 0}] expect(result, "intersection is correct").toEqual(expected) }) test('it correctly finds an intersection with multiple position transforms', () => { - const node = initSceneNode(m4fromPositionAndEuler([-2,0,0], [0,0,0]), { + const node = initSceneNode(m4fromPositionAndEuler({x: -2, y: 0, z: 0}, ROT_NONE), { vertices, material }) - const parentNode = initSceneNode(m4fromPositionAndEuler([-2,0,0], [0,0,0])) + const parentNode = initSceneNode(m4fromPositionAndEuler({ x: -2, y: 0, z: 0}, ROT_NONE)) setParent(node, parentNode) const ray: Ray = { - origin: [-11, 0.5, 0], - direction: [0, -1, 0] + origin: {x: -11, y: 0.5, z: 0}, + direction: {x: 0, y: -1, z: 0} } const result = rayIntersectsSceneNode(ray, parentNode) - const expected: Intersection[] = [{ point: [-11, 0.0, 0], triangleIdx: 0}] + const expected: Intersection[] = [{ point: { x: -11, y: 0.0, z: 0}, triangleIdx: 0}] expect(result, "intersection is correct").toEqual(expected) }) @@ -81,25 +82,36 @@ test('it correctly finds an intersection with multiple position transforms', () test('it correctly finds an intersection with rotation transform', () => { - const node = initSceneNode(m4fromPositionAndEuler([0,0,0], [0,0,Math.PI/4]), { + const node = initSceneNode(m4fromPositionAndEuler(POS_ORIGIN, {x: 0, y: 0, z: Math.PI/4}), { vertices, material }) const ray: Ray = { - origin: [-1, 2, 0], - direction: [0, -1, 0] + origin: { x:-1, y: 2, z: 0}, + direction: {x: 0, y: -1, z: 0} } const result = rayIntersectsSceneNode(ray, node) - const expected: Intersection[] = [{ point: [-1, -1, 0], triangleIdx: 0}] + const expected: Intersection[] = [{ point: {x: -1, y: -1, z: 0}, triangleIdx: 0}] for (let i = 0; i < expected.length; i++) { - const elementofResult = result[0]!.point[i]! - const elementOfExpected = expected[0]!.point[i]! - expect(elementofResult, "intersection element is correct") - .toBeCloseTo(elementOfExpected, 6) + const elementofResult = result[0] + const elementOfExpected = expected[0]! + + expect(elementofResult, "intersection element is preset") + .not.toBe(undefined) + + + expect(elementofResult!.point.x, "intersection point x is correct") + .toBeCloseTo(elementOfExpected.point.x, 6) + + expect(elementofResult!.point.y, "intersection point y is correct") + .toBeCloseTo(elementOfExpected.point.y, 6) + + expect(elementofResult!.point.z, "intersection point z is correct") + .toBeCloseTo(elementOfExpected.point.z, 6) } }) \ No newline at end of file diff --git a/ts-tests/raycastTriangle.test.ts b/ts-tests/raycastTriangle.test.ts index d4d88ba..46c023b 100644 --- a/ts-tests/raycastTriangle.test.ts +++ b/ts-tests/raycastTriangle.test.ts @@ -4,18 +4,22 @@ import { normalize } from 'demo-01-ts-webgl/lib/vec'; // triangle is symmetrical x-y and just a bit back from origin z -const triangle: Triangle = [[1,0,0.1], [0,1,0.1], [-1, 0, 0.1]] +const triangle: Triangle = [ + { x: 1, y: 0, z: 0.1}, + { x: 0, y: 1, z: 0.1}, + { x: -1, y: 0, z: 0.1} +] test('it correctly finds an intersection', () => { const ray: Ray = { - origin: [0.5, 0.5, 0], - direction: [0, 0, 1] + origin: {x: 0.5, y: 0.5, z: 0}, + direction: {x: 0, y: 0, z: 1 } } const result = rayIntersectsTriangle(ray, triangle) - const expected = [0.5, 0.5, 0.1] + const expected = {x: 0.5, y: 0.5, z: 0.1} expect(result, "intersection is correct").toEqual(expected) }) @@ -24,13 +28,13 @@ test(`it correctly finds an intersection even though the ray direction is not a unit vector`, () => { const ray: Ray = { - origin: [0.5, 0.5, 0], - direction: [0, 0, 2] + origin: {x: 0.5, y: 0.5, z: 0}, + direction: {x: 0, y: 0, z: 2 } } const result = rayIntersectsTriangle(ray, triangle) - const expected = [0.5, 0.5, 0.1] + const expected = {x: 0.5, y: 0.5, z: 0.1} expect(result, "intersection is correct").toEqual(expected) }) @@ -40,13 +44,13 @@ test(`it correctly finds an intersection and doesnt reach the triangle`, () => { const ray: Ray = { - origin: [0.5, 0.5, 0], - direction: [0, 0, 0.012] + origin: {x: 0.5, y: 0.5, z: 0}, + direction: {x: 0, y: 0, z: 0.012} } const result = rayIntersectsTriangle(ray, triangle) - const expected = [0.5, 0.5, 0.1] + const expected = {x: 0.5, y: 0.5, z: 0.1} expect(result, "intersection is correct").toEqual(expected) }) @@ -54,13 +58,13 @@ test(`it correctly finds an intersection test('it correctly finds another intersection', () => { const ray: Ray = { - origin: [0.2, 0.5, 0], - direction: [0, 0, 1] + origin: {x: 0.2, y: 0.5, z: 0}, + direction: {x: 0, y: 0, z: 1} } const result = rayIntersectsTriangle(ray, triangle) - const expected = [0.2, 0.5, 0.1] + const expected = {x: 0.2, y: 0.5, z: 0.1} expect(result, "intersection is correct").toEqual(expected) }) @@ -69,8 +73,8 @@ test('it correctly finds no intersection based on origin', () => { // pointing away from the triangle const ray: Ray = { - origin: [0.5, 0.5, 0.2], - direction: [0, 0, 1] + origin: {x: 0.5, y: 0.5, z: 0.2}, + direction: {x: 0, y: 0, z: 1 } } const result = rayIntersectsTriangle(ray, triangle) @@ -84,8 +88,8 @@ test('it correctly finds no intersection based on another origin', () => { // passing by the side of the triangle const ray: Ray = { - origin: [1.5, 0.5, 0.2], - direction: [0, 0, 1] + origin: { x: 1.5, y: 0.5, z: 0.2}, + direction: {x: 0, y: 0, z: 1 } } const result = rayIntersectsTriangle(ray, triangle) @@ -99,8 +103,8 @@ test('it correctly finds no intersection based on direction', () => { // this should intersect the triangles plane, but not the triangle itself const ray: Ray = { - origin: [0.5, 0.5, -10], - direction: normalize([0, 1, 1]) + origin: {x: 0.5, y: 0.5, z: -10}, + direction: normalize({x: 0, y: 1, z:1}) } const result = rayIntersectsTriangle(ray, triangle) @@ -112,11 +116,15 @@ test('it correctly finds no intersection based on direction', () => { test('it correctly finds no intersection based on origin', () => { - const triangle: Triangle = [ [ -10, 0, -10 ], [ -10, 0, 10 ], [ 10, 0, -10 ] ] + const triangle: Triangle = [ + { x: -10, y: 0, z: -10 }, + { x: -10, y: 0, z: 10 }, + { x: 10, y: 0, z: -10 } + ] // this should intersect the triangles plane, but not the triangle itself const ray: Ray = { - origin: [110, 0.5, 0], - direction: [0, -1, 0] + origin: {x: 110, y: 0.5, z: 0}, + direction: {x: 0, y: -1, z: 0} } const result = rayIntersectsTriangle(ray, triangle) @@ -128,11 +136,14 @@ test('it correctly finds no intersection based on origin', () => { test('it correctly finds no intersection based on origin', () => { - const triangle: Triangle = [ [ -10, 0, -10 ], [ -10, 0, 10 ], [ 10, 0, -10 ] ] + const triangle: Triangle = [ + { x: -10, y: 0, z: -10 }, + { x: -10, y: 0, z: 10 }, + { x: 10, y: 0, z: -10 } ] // this should intersect the triangles plane, but not the triangle itself const ray: Ray = { - origin: [1, 0.5, 0], - direction: [0, -1, 0] + origin: { x: 1, y: 0.5, z: 0}, + direction: {x: 0, y: -1, z: 0} } const result = rayIntersectsTriangle(ray, triangle) diff --git a/ts-tests/raycastVertices.test.ts b/ts-tests/raycastVertices.test.ts index 2e4699f..f0784ff 100644 --- a/ts-tests/raycastVertices.test.ts +++ b/ts-tests/raycastVertices.test.ts @@ -34,13 +34,13 @@ const meshVertices: Vertices = { test('it correctly finds an intersection in the first triangle', () => { const ray: Ray = { - origin: [-1, 0.5, 0], - direction: [0, -1, 0] + origin: { x: -1, y: 0.5, z: 0}, + direction: {x: 0, y: -1, z: 0} } const result = rayIntersectsVertices(ray, meshVertices) - const expected: Intersection[] = [{ point: [-1, 0.0, 0], triangleIdx: 0 }] + const expected: Intersection[] = [{ point: {x: -1, y: 0.0, z: 0}, triangleIdx: 0 }] expect(result, "intersection is correct").toEqual(expected) }) @@ -48,13 +48,13 @@ test('it correctly finds an intersection in the first triangle', () => { test('it correctly finds an intersection in the last triangle', () => { const ray: Ray = { - origin: [1, 0.5, 0], - direction: [0, -1, 0] + origin: {x: 1, y: 0.5, z: 0 }, + direction: {x: 0, y: -1, z: 0 } } const result = rayIntersectsVertices(ray, meshVertices) - const expected: Intersection = { point: [1, 0.0, 0], triangleIdx: 1 } + const expected: Intersection = { point: {x: 1, y: 0.0, z: 0}, triangleIdx: 1 } expect(result.length, "only one hit").toEqual(1) expect(result[0], "intersection is correct").toEqual(expected) @@ -63,8 +63,8 @@ test('it correctly finds an intersection in the last triangle', () => { test('it correctly finds no intersection', () => { const ray: Ray = { - origin: [110, 0.5, 0], - direction: [0, -1, 0] + origin: {x: 110, y: 0.5, z: 0}, + direction: {x: 0, y: -1, z: 0} } const result = rayIntersectsVertices(ray, meshVertices) diff --git a/ts-tests/scene.test.ts b/ts-tests/scene.test.ts index c4cbd66..4120eb8 100644 --- a/ts-tests/scene.test.ts +++ b/ts-tests/scene.test.ts @@ -1,14 +1,14 @@ import { expect, test } from 'vitest' import { setParent, initSceneNode } from "demo-01-ts-webgl/lib/scene"; import { m4fromPositionAndEuler } from 'demo-01-ts-webgl/lib/mat4'; +import { POS_ORIGIN, ROT_NONE } from 'demo-01-ts-webgl/lib/vec'; test('setParent updates parent and children correctly', () => { -const childNode = initSceneNode(m4fromPositionAndEuler([1, 1, 1], [0, 0, 0])) +const childNode = initSceneNode(m4fromPositionAndEuler({x: 1, y: 1, z: 1}, ROT_NONE)) -const parentNode1 = initSceneNode(m4fromPositionAndEuler([0, 0, 0], [0, 0, 0])) - -const parentNode2 = initSceneNode(m4fromPositionAndEuler([0, 0, 0], [0, 0, 0])) +const parentNode1 = initSceneNode(m4fromPositionAndEuler(POS_ORIGIN, ROT_NONE)) +const parentNode2 = initSceneNode(m4fromPositionAndEuler(POS_ORIGIN, ROT_NONE)) setParent(childNode, parentNode1); From d80a510326fb78b845c41579ab0488bf83d53b74 Mon Sep 17 00:00:00 2001 From: Tom Greenwood Date: Mon, 5 Jan 2026 13:25:50 +0000 Subject: [PATCH 02/10] tidy --- demo-01-ts-webgl/lib/mat4.ts | 81 +----------------------------------- 1 file changed, 2 insertions(+), 79 deletions(-) diff --git a/demo-01-ts-webgl/lib/mat4.ts b/demo-01-ts-webgl/lib/mat4.ts index 4f2cf43..88f896d 100644 --- a/demo-01-ts-webgl/lib/mat4.ts +++ b/demo-01-ts-webgl/lib/mat4.ts @@ -1,5 +1,5 @@ import { Ray } from './raycast'; -import { Vec3, Vec4, normalize, subtractVectors, cross, QUAT_ORIGIN, vec3ToArray, vec4ToArray } from './vec' +import { Vec3, Vec4, normalize, subtractVectors, cross, vec3ToArray, vec4ToArray } from './vec' export type Mat4 = [ @@ -9,8 +9,6 @@ export type Mat4 = [ number, number, number, number, ] - - export function m4lookAt(cameraPosition: Vec3, target: Vec3, up: Vec3): Mat4 { const zAxis = normalize( subtractVectors(cameraPosition, target)); @@ -324,33 +322,10 @@ export function m4vectorMultiply(v: Vec4, m: Mat4): Vec4 { } return { x: dst[0], y: dst[1], z: dst[2], w: dst[3] }; - // const m00 = m[0 * 4 + 0]!; - // const m01 = m[0 * 4 + 1]!; - // const m02 = m[0 * 4 + 2]!; - // const m03 = m[0 * 4 + 3]!; - // const m10 = m[1 * 4 + 0]!; - // const m11 = m[1 * 4 + 1]!; - // const m12 = m[1 * 4 + 2]!; - // const m13 = m[1 * 4 + 3]!; - // const m20 = m[2 * 4 + 0]!; - // const m21 = m[2 * 4 + 1]!; - // const m22 = m[2 * 4 + 2]!; - // const m23 = m[2 * 4 + 3]!; - // const m30 = m[3 * 4 + 0]!; - // const m31 = m[3 * 4 + 1]!; - // const m32 = m[3 * 4 + 2]!; - // const m33 = m[3 * 4 + 3]!; - - // return { - // x: m00 * v.x + m01 * v.y + m02 * v.z + m03 * v.w, - // y: m10 * v.x + m11 * v.y + m12 * v.z + m13 * v.w, - // z: m20 * v.x + m21 * v.y + m22 * v.z + m23 * v.w, - // w: m30 * v.x + m31 * v.y + m32 * v.z + m33 * v.w - // } } export function m4PositionMultiply(v: Vec3, m: Mat4): Vec3 { - // const v1: Vec4 = {...v, w: 1} + const vArray: [number, number, number, number ] = [...vec3ToArray(v), 1] const dst: [number, number, number, number] = [0,0,0,0]; for (let i = 0; i < 4; ++i) { @@ -359,32 +334,6 @@ export function m4PositionMultiply(v: Vec3, m: Mat4): Vec3 { } } - // const m00 = m[0 * 4 + 0]!; - // const m01 = m[0 * 4 + 1]!; - // const m02 = m[0 * 4 + 2]!; - // const m03 = m[0 * 4 + 3]!; - // const m10 = m[1 * 4 + 0]!; - // const m11 = m[1 * 4 + 1]!; - // const m12 = m[1 * 4 + 2]!; - // const m13 = m[1 * 4 + 3]!; - // const m20 = m[2 * 4 + 0]!; - // const m21 = m[2 * 4 + 1]!; - // const m22 = m[2 * 4 + 2]!; - // const m23 = m[2 * 4 + 3]!; - // const m30 = m[3 * 4 + 0]!; - // const m31 = m[3 * 4 + 1]!; - // const m32 = m[3 * 4 + 2]!; - // const m33 = m[3 * 4 + 3]!; - - - // const dst: Vec4 = { - // x: m00 * v1.x + m01 * v1.y + m02 * v1.z + m03 * v1.w, - // y: m10 * v1.x + m11 * v1.y + m12 * v1.z + m13 * v1.w, - // z: m20 * v1.x + m21 * v1.y + m22 * v1.z + m23 * v1.w, - // w: m30 * v1.x + m31 * v1.y + m32 * v1.z + m33 * v1.w - // } - - // return {x: dst.x/dst.w, y: dst.y/dst.w, z: dst.z/dst.w }; return {x: dst[0]/dst[3], y: dst[1]/dst[3], z: dst[2]/dst[3] } } @@ -400,32 +349,6 @@ export function m4DirectionMultiply(v: Vec3, m: Mat4): Vec3 { return { x: dst[0], y: dst[1], z: dst[2] }; - // const m00 = m[0 * 4 + 0]!; - // const m01 = m[0 * 4 + 1]!; - // const m02 = m[0 * 4 + 2]!; - // const m03 = m[0 * 4 + 3]!; - // const m10 = m[1 * 4 + 0]!; - // const m11 = m[1 * 4 + 1]!; - // const m12 = m[1 * 4 + 2]!; - // const m13 = m[1 * 4 + 3]!; - // const m20 = m[2 * 4 + 0]!; - // const m21 = m[2 * 4 + 1]!; - // const m22 = m[2 * 4 + 2]!; - // const m23 = m[2 * 4 + 3]!; - // const m30 = m[3 * 4 + 0]!; - // const m31 = m[3 * 4 + 1]!; - // const m32 = m[3 * 4 + 2]!; - // const m33 = m[3 * 4 + 3]!; - - // const v1: Vec4 = {...v, w: 0} - - // const dst: Vec4 = { - // x: m00 * v1.x + m01 * v1.y + m02 * v1.z + m03 * v1.w, - // y: m10 * v1.x + m11 * v1.y + m12 * v1.z + m13 * v1.w, - // z: m20 * v1.x + m21 * v1.y + m22 * v1.z + m23 * v1.w, - // w: m30 * v1.x + m31 * v1.y + m32 * v1.z + m33 * v1.w - // } - // return { x: dst.x, y: dst.y, z: dst.z }; } export function m4RayMultiply(ray: Ray, m: Mat4) { From dda8a67645c0b8a79005e3f6002dc776e7a23cd8 Mon Sep 17 00:00:00 2001 From: Tom Greenwood Date: Mon, 5 Jan 2026 15:39:30 +0000 Subject: [PATCH 03/10] more stricter types --- demo-01-ts-webgl/lib/mat4.ts | 59 ++++++++++++++++++++++++++------ demo-01-ts-webgl/lib/raycast.ts | 4 +-- demo-01-ts-webgl/lib/vec.ts | 21 +++++++++++- ts-tests/raycastTriangle.test.ts | 4 +-- 4 files changed, 73 insertions(+), 15 deletions(-) diff --git a/demo-01-ts-webgl/lib/mat4.ts b/demo-01-ts-webgl/lib/mat4.ts index 88f896d..3f3fab5 100644 --- a/demo-01-ts-webgl/lib/mat4.ts +++ b/demo-01-ts-webgl/lib/mat4.ts @@ -1,5 +1,5 @@ import { Ray } from './raycast'; -import { Vec3, Vec4, normalize, subtractVectors, cross, vec3ToArray, vec4ToArray } from './vec' +import { Vec3, Vec4, subtractVectors, cross, vec3ToArray, vec4ToArray, normalize } from './vec' export type Mat4 = [ @@ -9,11 +9,51 @@ export type Mat4 = [ number, number, number, number, ] +export type Mat4Scaling = [ + number, 0, 0, 0, + 0, number, 0, 0, + 0, 0, number, 0, + 0, 0, 0, 1, +] + +export type Mat4Translation = [ + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + number, number, number, 1, +] + +export type Mat4XRotation = [ + 1, 0, 0, 0, + 0, number, number, 0, + 0, number, number, 0, + 0, 0, 0, 1, +] + +export type Mat4YRotation = [ + number, 0, number, 0, + 0, 1, 0, 0, + number, 0, number, 0, + 0, 0, 0, 1, +] + +export type Mat4ZRotation = [ + number, number, 0, 0, + number, number, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1, +] + export function m4lookAt(cameraPosition: Vec3, target: Vec3, up: Vec3): Mat4 { - const zAxis = normalize( - subtractVectors(cameraPosition, target)); - const xAxis = normalize(cross(up, zAxis)); - const yAxis = normalize(cross(zAxis, xAxis)); + const zAxis = subtractVectors(cameraPosition, target) + normalize(zAxis) + + const xAxis = cross(up, zAxis); + normalize(xAxis) + + const yAxis = cross(zAxis, xAxis); + normalize(yAxis) + return [ xAxis.x, xAxis.y, xAxis.z, 0, @@ -117,7 +157,7 @@ export function m4multiply(a: Mat4, b: Mat4): Mat4 { ]; } -export function m4translation(tx: number, ty: number, tz: number): Mat4 { +export function m4translation(tx: number, ty: number, tz: number): Mat4Translation { return [ 1, 0, 0, 0, 0, 1, 0, 0, @@ -126,7 +166,7 @@ export function m4translation(tx: number, ty: number, tz: number): Mat4 { ]; } -export function m4xRotation(angleInRadians: number): Mat4 { +export function m4xRotation(angleInRadians: number): Mat4XRotation { const c = Math.cos(angleInRadians); const s = Math.sin(angleInRadians); @@ -138,7 +178,7 @@ export function m4xRotation(angleInRadians: number): Mat4 { ]; } -export function m4yRotation(angleInRadians: number): Mat4 { +export function m4yRotation(angleInRadians: number): Mat4YRotation { const c = Math.cos(angleInRadians); const s = Math.sin(angleInRadians); @@ -150,7 +190,7 @@ export function m4yRotation(angleInRadians: number): Mat4 { ]; } -export function m4zRotation(angleInRadians: number): Mat4 { +export function m4zRotation(angleInRadians: number): Mat4ZRotation { const c = Math.cos(angleInRadians); const s = Math.sin(angleInRadians); @@ -197,7 +237,6 @@ export function m4scaling(sx: number, sy: number, sz: number): Mat4 { * @param {Matrix4} m matrix to transpose. * @param {Matrix4} [dst] optional matrix to store result * @return {Matrix4} dst or a new matrix if none provided - * @memberOf module:webgl-3d-math */ export function m4transpose(m: Mat4) { const dst: Mat4 = [ diff --git a/demo-01-ts-webgl/lib/raycast.ts b/demo-01-ts-webgl/lib/raycast.ts index 3c8e3ea..43cf2fc 100644 --- a/demo-01-ts-webgl/lib/raycast.ts +++ b/demo-01-ts-webgl/lib/raycast.ts @@ -187,11 +187,11 @@ export function getWorldRayFromClipSpaceAndCamera( const rayDirection = subtractVectors(worldFar, worldNear); - const rayDirNorm = normalize(rayDirection); + normalize(rayDirection); const worldRay: Ray = { origin: rayOrigin, - direction: rayDirNorm as Vec3 + direction: rayDirection }; return worldRay diff --git a/demo-01-ts-webgl/lib/vec.ts b/demo-01-ts-webgl/lib/vec.ts index 8158569..526c9e2 100644 --- a/demo-01-ts-webgl/lib/vec.ts +++ b/demo-01-ts-webgl/lib/vec.ts @@ -49,7 +49,26 @@ export function scaleVector(vec: Vec3, scalar: number): Vec3 { } } -export function normalize(v: Vec3): Vec3 { +// operates in-place +export function normalize(v: Vec3): void { + const length = Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z); + // make sure we don't divide by 0. + if (length > 0.00001) { + + v.x /= length + v.y /= length + v.z /= length + + } else { + + v.x = 0, + v.y = 0, + v.z = 0 + }; +} + +// immutable, returns a new one +export function normalized(v: Vec3): Vec3 { const length = Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z); // make sure we don't divide by 0. if (length > 0.00001) { diff --git a/ts-tests/raycastTriangle.test.ts b/ts-tests/raycastTriangle.test.ts index 46c023b..6bb7a84 100644 --- a/ts-tests/raycastTriangle.test.ts +++ b/ts-tests/raycastTriangle.test.ts @@ -1,6 +1,6 @@ import { expect, test } from 'vitest' import { Ray, rayIntersectsTriangle, Triangle } from "demo-01-ts-webgl/lib/raycast"; -import { normalize } from 'demo-01-ts-webgl/lib/vec'; +import { normalized } from 'demo-01-ts-webgl/lib/vec'; // triangle is symmetrical x-y and just a bit back from origin z @@ -104,7 +104,7 @@ test('it correctly finds no intersection based on direction', () => { // this should intersect the triangles plane, but not the triangle itself const ray: Ray = { origin: {x: 0.5, y: 0.5, z: -10}, - direction: normalize({x: 0, y: 1, z:1}) + direction: normalized({x: 0, y: 1, z:1}) } const result = rayIntersectsTriangle(ray, triangle) From 0e5362e7e4aa9d12223ebab7d9479fc41ad968b9 Mon Sep 17 00:00:00 2001 From: Tom Greenwood Date: Tue, 6 Jan 2026 09:07:41 +0000 Subject: [PATCH 04/10] tidy --- demo-01-ts-webgl/index.ts | 34 ++++++++++++++++--------------- demo-01-ts-webgl/lib/mat4.ts | 39 +++++++++--------------------------- 2 files changed, 28 insertions(+), 45 deletions(-) diff --git a/demo-01-ts-webgl/index.ts b/demo-01-ts-webgl/index.ts index 87ff742..568ee07 100644 --- a/demo-01-ts-webgl/index.ts +++ b/demo-01-ts-webgl/index.ts @@ -6,11 +6,11 @@ import { Camera } from './lib/camera' import { initBasicRenderProgram, drawScene, createShadowMap, initShadowRenderProgram } from './lib/BasicRenderProgram' import { loadObj } from './lib/loaders/ObjLoader' import { InputState } from './lib/input' -import { m4fromPositionAndEuler, m4lookAt, m4vectorMultiply, m4yRotation } from './lib/mat4' +import { m4fromPositionAndEuler, m4lookAt } from './lib/mat4' import { initGlState } from './lib/gl' import { getWorldRayFromClipSpaceAndCamera, rayIntersectsScene, sortBySceneDepth } from './lib/raycast' import { getPointerClickInClipSpace } from './lib/events' -import { Color, POS_ORIGIN, ROT_NONE, Vec3, Vec4, calculateOrbitPosition } from './lib/vec' +import { Color, POS_ORIGIN, ROT_NONE, Vec3, calculateOrbitPosition } from './lib/vec' type NodeName = "yellow tree" | "orange tree" | "green tree" | "floor"; @@ -250,12 +250,12 @@ canvas.addEventListener('pointerdown', () => { /////////////////////////// -let lastTime = 0; +// let lastTime = 0; function animate(time: DOMHighResTimeStamp) { time *= 0.001 // convert from millis to seconds - const dt = time - lastTime; - lastTime = time; - updateLight(pointLight, dt) + // const dt = time - lastTime; + // lastTime = time; + // updateLight(pointLight, dt) // this both break under the shadow mapping // updateDirectionalLight(directionalLight, time) resizeCanvasToDisplaySize(canvas); camera.aspect = canvas.clientWidth / canvas.clientHeight; @@ -302,22 +302,24 @@ function resizeCanvasToDisplaySize(canvas: HTMLCanvasElement): void { } } + + // function updateDirectionalLight(light: DirectionalLight, time: number) { // const oldRotation = light.rotation -// light.rotation = [oldRotation[0], Math.sin(time), oldRotation[2]] +// light.rotation = { x: oldRotation.x, y: Math.sin(time), z: oldRotation.z } // } -function updateLight(pointLight: PointLight, dt: number) { - const rotator = m4yRotation(Math.PI / (dt * 10000)); - const oldTransform: Vec4 = { - ...pointLight.position, - w: 0.0 - }; +// function updateLight(pointLight: PointLight, dt: number) { +// const rotator = m4yRotation(Math.PI / (dt * 10000)); +// const oldTransform: Vec4 = { +// ...pointLight.position, +// w: 0.0 +// }; - const newTransform = m4vectorMultiply(oldTransform, rotator); - pointLight.position = { x: newTransform.x, y: newTransform.y, z: newTransform.z } -} \ No newline at end of file +// const newTransform = m4PositionMultiply(oldTransform, rotator); +// pointLight.position = { x: newTransform.x, y: newTransform.y, z: newTransform.z } +// } \ No newline at end of file diff --git a/demo-01-ts-webgl/lib/mat4.ts b/demo-01-ts-webgl/lib/mat4.ts index 3f3fab5..370b877 100644 --- a/demo-01-ts-webgl/lib/mat4.ts +++ b/demo-01-ts-webgl/lib/mat4.ts @@ -66,7 +66,14 @@ export function m4lookAt(cameraPosition: Vec3, target: Vec3, up: Vec3): Mat4 { ]; } -export function m4perspective(fieldOfViewInRadians: number, aspect: number, near: number, far: number): Mat4 { +export type Mat4Projection = [ + number, 0, 0, 0, + 0, number, 0, 0, + 0, 0, number,-1|0, + number, number, number, 0|1, +] + +export function m4perspective(fieldOfViewInRadians: number, aspect: number, near: number, far: number): Mat4Projection { const f = Math.tan(Math.PI * 0.5 - 0.5 * fieldOfViewInRadians); const rangeInv = 1.0 / (near - far); @@ -80,7 +87,7 @@ export function m4perspective(fieldOfViewInRadians: number, aspect: number, near -export function m4orthographic(left: number, right: number, bottom: number, top: number, near: number, far: number): Mat4 { +export function m4orthographic(left: number, right: number, bottom: number, top: number, near: number, far: number): Mat4Projection { const lr = 1 / (left - right); const bt = 1 / (bottom - top); const nf = 1 / (near - far); @@ -93,15 +100,6 @@ export function m4orthographic(left: number, right: number, bottom: number, top: ]; } -export function m4projection(width: number, height: number, depth: number): Mat4 { - // Note: This matrix flips the Y axis so 0 is at the top. - return [ - 2 / width, 0, 0, 0, - 0, -2 / height, 0, 0, - 0, 0, 2 / depth, 0, - -1, 1, 0, 1, - ]; - } export function m4multiply(a: Mat4, b: Mat4): Mat4 { @@ -351,17 +349,6 @@ export function m4inverse(m: Mat4): Mat4 { ]; } -export function m4vectorMultiply(v: Vec4, m: Mat4): Vec4 { - const dst: [number, number, number, number] = [0,0,0,0]; - const vArray = vec4ToArray(v) - for (let i = 0; i < 4; ++i) { - for (let j = 0; j < 4; ++j) { - dst[i]! += vArray[j]! * m[j * 4 + i]!; // ts is not smart enough to see that we set dst[i] to a number already - } - } - return { x: dst[0], y: dst[1], z: dst[2], w: dst[3] }; - - } export function m4PositionMultiply(v: Vec3, m: Mat4): Vec3 { @@ -390,13 +377,7 @@ export function m4DirectionMultiply(v: Vec3, m: Mat4): Vec3 { } -export function m4RayMultiply(ray: Ray, m: Mat4) { - return { - origin: m4PositionMultiply(ray.origin, m), - direction: m4DirectionMultiply(ray.direction, m) - - } -} + export function m4fromPositionAndEuler(position: Vec3, euler: Vec3): Mat4 { let mat4 = m4translate(m4yRotation(0), position.x, position.y, position.z) ; From f353c71318eaf22bc8e49644cf3c6753de7fa155 Mon Sep 17 00:00:00 2001 From: Tom Greenwood Date: Tue, 6 Jan 2026 09:22:34 +0000 Subject: [PATCH 05/10] start m4 structure change --- demo-01-ts-webgl/lib/mat4.ts | 244 +++++++++++++++++------------------ 1 file changed, 121 insertions(+), 123 deletions(-) diff --git a/demo-01-ts-webgl/lib/mat4.ts b/demo-01-ts-webgl/lib/mat4.ts index 370b877..564cd10 100644 --- a/demo-01-ts-webgl/lib/mat4.ts +++ b/demo-01-ts-webgl/lib/mat4.ts @@ -44,6 +44,47 @@ export type Mat4ZRotation = [ 0, 0, 0, 1, ] +type Mat4Positions = { + m00: number + m01: number + m02: number + m03: number + m10: number + m11: number + m12: number + m13: number + m20: number + m21: number + m22: number + m23: number + m30: number + m31: number + m32: number + m33: number +} + +function m4AsPositions(m: Mat4): Mat4Positions { + return { + m00 : m[0 * 4 + 0]!, + m01 : m[0 * 4 + 1]!, + m02 : m[0 * 4 + 2]!, + m03 : m[0 * 4 + 3]!, + m10 : m[1 * 4 + 0]!, + m11 : m[1 * 4 + 1]!, + m12 : m[1 * 4 + 2]!, + m13 : m[1 * 4 + 3]!, + m20 : m[2 * 4 + 0]!, + m21 : m[2 * 4 + 1]!, + m22 : m[2 * 4 + 2]!, + m23 : m[2 * 4 + 3]!, + m30 : m[3 * 4 + 0]!, + m31 : m[3 * 4 + 1]!, + m32 : m[3 * 4 + 2]!, + m33 : m[3 * 4 + 3]!, + } +} + + export function m4lookAt(cameraPosition: Vec3, target: Vec3, up: Vec3): Mat4 { const zAxis = subtractVectors(cameraPosition, target) normalize(zAxis) @@ -103,55 +144,26 @@ export function m4orthographic(left: number, right: number, bottom: number, top: export function m4multiply(a: Mat4, b: Mat4): Mat4 { - const a00 = a[0 * 4 + 0]!; - const a01 = a[0 * 4 + 1]!; - const a02 = a[0 * 4 + 2]!; - const a03 = a[0 * 4 + 3]!; - const a10 = a[1 * 4 + 0]!; - const a11 = a[1 * 4 + 1]!; - const a12 = a[1 * 4 + 2]!; - const a13 = a[1 * 4 + 3]!; - const a20 = a[2 * 4 + 0]!; - const a21 = a[2 * 4 + 1]!; - const a22 = a[2 * 4 + 2]!; - const a23 = a[2 * 4 + 3]!; - const a30 = a[3 * 4 + 0]!; - const a31 = a[3 * 4 + 1]!; - const a32 = a[3 * 4 + 2]!; - const a33 = a[3 * 4 + 3]!; - const b00 = b[0 * 4 + 0]!; - const b01 = b[0 * 4 + 1]!; - const b02 = b[0 * 4 + 2]!; - const b03 = b[0 * 4 + 3]!; - const b10 = b[1 * 4 + 0]!; - const b11 = b[1 * 4 + 1]!; - const b12 = b[1 * 4 + 2]!; - const b13 = b[1 * 4 + 3]!; - const b20 = b[2 * 4 + 0]!; - const b21 = b[2 * 4 + 1]!; - const b22 = b[2 * 4 + 2]!; - const b23 = b[2 * 4 + 3]!; - const b30 = b[3 * 4 + 0]!; - const b31 = b[3 * 4 + 1]!; - const b32 = b[3 * 4 + 2]!; - const b33 = b[3 * 4 + 3]!; + const ap = m4AsPositions(a); + const bp = m4AsPositions(b); + return [ - b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30, - b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31, - b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32, - b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33, - b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30, - b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31, - b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32, - b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33, - b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30, - b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31, - b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32, - b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33, - b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30, - b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31, - b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32, - b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33, + bp.m00 * ap.m00 + bp.m01 * ap.m10 + bp.m02 * ap.m20 + bp.m03 * ap.m30, + bp.m00 * ap.m01 + bp.m01 * ap.m11 + bp.m02 * ap.m21 + bp.m03 * ap.m31, + bp.m00 * ap.m02 + bp.m01 * ap.m12 + bp.m02 * ap.m22 + bp.m03 * ap.m32, + bp.m00 * ap.m03 + bp.m01 * ap.m13 + bp.m02 * ap.m23 + bp.m03 * ap.m33, + bp.m10 * ap.m00 + bp.m11 * ap.m10 + bp.m12 * ap.m20 + bp.m13 * ap.m30, + bp.m10 * ap.m01 + bp.m11 * ap.m11 + bp.m12 * ap.m21 + bp.m13 * ap.m31, + bp.m10 * ap.m02 + bp.m11 * ap.m12 + bp.m12 * ap.m22 + bp.m13 * ap.m32, + bp.m10 * ap.m03 + bp.m11 * ap.m13 + bp.m12 * ap.m23 + bp.m13 * ap.m33, + bp.m20 * ap.m00 + bp.m21 * ap.m10 + bp.m22 * ap.m20 + bp.m23 * ap.m30, + bp.m20 * ap.m01 + bp.m21 * ap.m11 + bp.m22 * ap.m21 + bp.m23 * ap.m31, + bp.m20 * ap.m02 + bp.m21 * ap.m12 + bp.m22 * ap.m22 + bp.m23 * ap.m32, + bp.m20 * ap.m03 + bp.m21 * ap.m13 + bp.m22 * ap.m23 + bp.m23 * ap.m33, + bp.m30 * ap.m00 + bp.m31 * ap.m10 + bp.m32 * ap.m20 + bp.m33 * ap.m30, + bp.m30 * ap.m01 + bp.m31 * ap.m11 + bp.m32 * ap.m21 + bp.m33 * ap.m31, + bp.m30 * ap.m02 + bp.m31 * ap.m12 + bp.m32 * ap.m22 + bp.m33 * ap.m32, + bp.m30 * ap.m03 + bp.m31 * ap.m13 + bp.m32 * ap.m23 + bp.m33 * ap.m33, ]; } @@ -265,87 +277,73 @@ export function m4transpose(m: Mat4) { } export function m4inverse(m: Mat4): Mat4 { - const m00 = m[0 * 4 + 0]!; - const m01 = m[0 * 4 + 1]!; - const m02 = m[0 * 4 + 2]!; - const m03 = m[0 * 4 + 3]!; - const m10 = m[1 * 4 + 0]!; - const m11 = m[1 * 4 + 1]!; - const m12 = m[1 * 4 + 2]!; - const m13 = m[1 * 4 + 3]!; - const m20 = m[2 * 4 + 0]!; - const m21 = m[2 * 4 + 1]!; - const m22 = m[2 * 4 + 2]!; - const m23 = m[2 * 4 + 3]!; - const m30 = m[3 * 4 + 0]!; - const m31 = m[3 * 4 + 1]!; - const m32 = m[3 * 4 + 2]!; - const m33 = m[3 * 4 + 3]!; - const tmp_0 = m22 * m33; - const tmp_1 = m32 * m23; - const tmp_2 = m12 * m33; - const tmp_3 = m32 * m13; - const tmp_4 = m12 * m23; - const tmp_5 = m22 * m13; - const tmp_6 = m02 * m33; - const tmp_7 = m32 * m03; - const tmp_8 = m02 * m23; - const tmp_9 = m22 * m03; - const tmp_10 = m02 * m13; - const tmp_11 = m12 * m03; - const tmp_12 = m20 * m31; - const tmp_13 = m30 * m21; - const tmp_14 = m10 * m31; - const tmp_15 = m30 * m11; - const tmp_16 = m10 * m21; - const tmp_17 = m20 * m11; - const tmp_18 = m00 * m31; - const tmp_19 = m30 * m01; - const tmp_20 = m00 * m21; - const tmp_21 = m20 * m01; - const tmp_22 = m00 * m11; - const tmp_23 = m10 * m01; - - const t0 = (tmp_0 * m11 + tmp_3 * m21 + tmp_4 * m31) - - (tmp_1 * m11 + tmp_2 * m21 + tmp_5 * m31); - const t1 = (tmp_1 * m01 + tmp_6 * m21 + tmp_9 * m31) - - (tmp_0 * m01 + tmp_7 * m21 + tmp_8 * m31); - const t2 = (tmp_2 * m01 + tmp_7 * m11 + tmp_10 * m31) - - (tmp_3 * m01 + tmp_6 * m11 + tmp_11 * m31); - const t3 = (tmp_5 * m01 + tmp_8 * m11 + tmp_11 * m21) - - (tmp_4 * m01 + tmp_9 * m11 + tmp_10 * m21); - - const d = 1.0 / (m00 * t0 + m10 * t1 + m20 * t2 + m30 * t3); + const p = m4AsPositions(m) + + const tmp_0 = p.m22 * p.m33; + const tmp_1 = p.m32 * p.m23; + const tmp_2 = p.m12 * p.m33; + const tmp_3 = p.m32 * p.m13; + const tmp_4 = p.m12 * p.m23; + const tmp_5 = p.m22 * p.m13; + const tmp_6 = p.m02 * p.m33; + const tmp_7 = p.m32 * p.m03; + const tmp_8 = p.m02 * p.m23; + const tmp_9 = p.m22 * p.m03; + const tmp_10 = p.m02 * p.m13; + const tmp_11 = p.m12 * p.m03; + const tmp_12 = p.m20 * p.m31; + const tmp_13 = p.m30 * p.m21; + const tmp_14 = p.m10 * p.m31; + const tmp_15 = p.m30 * p.m11; + const tmp_16 = p.m10 * p.m21; + const tmp_17 = p.m20 * p.m11; + const tmp_18 = p.m00 * p.m31; + const tmp_19 = p.m30 * p.m01; + const tmp_20 = p.m00 * p.m21; + const tmp_21 = p.m20 * p.m01; + const tmp_22 = p.m00 * p.m11; + const tmp_23 = p.m10 * p.m01; + + const t0 = (tmp_0 * p.m11 + tmp_3 * p.m21 + tmp_4 * p.m31) - + (tmp_1 * p.m11 + tmp_2 * p.m21 + tmp_5 * p.m31); + const t1 = (tmp_1 * p.m01 + tmp_6 * p.m21 + tmp_9 * p.m31) - + (tmp_0 * p.m01 + tmp_7 * p.m21 + tmp_8 * p.m31); + const t2 = (tmp_2 * p.m01 + tmp_7 * p.m11 + tmp_10 * p.m31) - + (tmp_3 * p.m01 + tmp_6 * p.m11 + tmp_11 * p.m31); + const t3 = (tmp_5 * p.m01 + tmp_8 * p.m11 + tmp_11 * p.m21) - + (tmp_4 * p.m01 + tmp_9 * p.m11 + tmp_10 * p.m21); + + const d = 1.0 / (p.m00 * t0 + p.m10 * t1 + p.m20 * t2 + p.m30 * t3); return [ d * t0, d * t1, d * t2, d * t3, - d * ((tmp_1 * m10 + tmp_2 * m20 + tmp_5 * m30) - - (tmp_0 * m10 + tmp_3 * m20 + tmp_4 * m30)), - d * ((tmp_0 * m00 + tmp_7 * m20 + tmp_8 * m30) - - (tmp_1 * m00 + tmp_6 * m20 + tmp_9 * m30)), - d * ((tmp_3 * m00 + tmp_6 * m10 + tmp_11 * m30) - - (tmp_2 * m00 + tmp_7 * m10 + tmp_10 * m30)), - d * ((tmp_4 * m00 + tmp_9 * m10 + tmp_10 * m20) - - (tmp_5 * m00 + tmp_8 * m10 + tmp_11 * m20)), - d * ((tmp_12 * m13 + tmp_15 * m23 + tmp_16 * m33) - - (tmp_13 * m13 + tmp_14 * m23 + tmp_17 * m33)), - d * ((tmp_13 * m03 + tmp_18 * m23 + tmp_21 * m33) - - (tmp_12 * m03 + tmp_19 * m23 + tmp_20 * m33)), - d * ((tmp_14 * m03 + tmp_19 * m13 + tmp_22 * m33) - - (tmp_15 * m03 + tmp_18 * m13 + tmp_23 * m33)), - d * ((tmp_17 * m03 + tmp_20 * m13 + tmp_23 * m23) - - (tmp_16 * m03 + tmp_21 * m13 + tmp_22 * m23)), - d * ((tmp_14 * m22 + tmp_17 * m32 + tmp_13 * m12) - - (tmp_16 * m32 + tmp_12 * m12 + tmp_15 * m22)), - d * ((tmp_20 * m32 + tmp_12 * m02 + tmp_19 * m22) - - (tmp_18 * m22 + tmp_21 * m32 + tmp_13 * m02)), - d * ((tmp_18 * m12 + tmp_23 * m32 + tmp_15 * m02) - - (tmp_22 * m32 + tmp_14 * m02 + tmp_19 * m12)), - d * ((tmp_22 * m22 + tmp_16 * m02 + tmp_21 * m12) - - (tmp_20 * m12 + tmp_23 * m22 + tmp_17 * m02)) + d * ((tmp_1 * p.m10 + tmp_2 * p.m20 + tmp_5 * p.m30) - + (tmp_0 * p.m10 + tmp_3 * p.m20 + tmp_4 * p.m30)), + d * ((tmp_0 * p.m00 + tmp_7 * p.m20 + tmp_8 * p.m30) - + (tmp_1 * p.m00 + tmp_6 * p.m20 + tmp_9 * p.m30)), + d * ((tmp_3 * p.m00 + tmp_6 * p.m10 + tmp_11 * p.m30) - + (tmp_2 * p.m00 + tmp_7 * p.m10 + tmp_10 * p.m30)), + d * ((tmp_4 * p.m00 + tmp_9 * p.m10 + tmp_10 * p.m20) - + (tmp_5 * p.m00 + tmp_8 * p.m10 + tmp_11 * p.m20)), + d * ((tmp_12 * p.m13 + tmp_15 * p.m23 + tmp_16 * p.m33) - + (tmp_13 * p.m13 + tmp_14 * p.m23 + tmp_17 * p.m33)), + d * ((tmp_13 * p.m03 + tmp_18 * p.m23 + tmp_21 * p.m33) - + (tmp_12 * p.m03 + tmp_19 * p.m23 + tmp_20 * p.m33)), + d * ((tmp_14 * p.m03 + tmp_19 * p.m13 + tmp_22 * p.m33) - + (tmp_15 * p.m03 + tmp_18 * p.m13 + tmp_23 * p.m33)), + d * ((tmp_17 * p.m03 + tmp_20 * p.m13 + tmp_23 * p.m23) - + (tmp_16 * p.m03 + tmp_21 * p.m13 + tmp_22 * p.m23)), + d * ((tmp_14 * p.m22 + tmp_17 * p.m32 + tmp_13 * p.m12) - + (tmp_16 * p.m32 + tmp_12 * p.m12 + tmp_15 * p.m22)), + d * ((tmp_20 * p.m32 + tmp_12 * p.m02 + tmp_19 * p.m22) - + (tmp_18 * p.m22 + tmp_21 * p.m32 + tmp_13 * p.m02)), + d * ((tmp_18 * p.m12 + tmp_23 * p.m32 + tmp_15 * p.m02) - + (tmp_22 * p.m32 + tmp_14 * p.m02 + tmp_19 * p.m12)), + d * ((tmp_22 * p.m22 + tmp_16 * p.m02 + tmp_21 * p.m12) - + (tmp_20 * p.m12 + tmp_23 * p.m22 + tmp_17 * p.m02)) ]; } From 21f040be425500fbf0919c1aeff3f61db92690a3 Mon Sep 17 00:00:00 2001 From: Tom Greenwood Date: Tue, 6 Jan 2026 11:07:47 +0000 Subject: [PATCH 06/10] more-m4-structure-change --- demo-01-ts-webgl/lib/mat4.ts | 133 ++++++++++++++++++++++++++++++----- 1 file changed, 114 insertions(+), 19 deletions(-) diff --git a/demo-01-ts-webgl/lib/mat4.ts b/demo-01-ts-webgl/lib/mat4.ts index 564cd10..64e92ec 100644 --- a/demo-01-ts-webgl/lib/mat4.ts +++ b/demo-01-ts-webgl/lib/mat4.ts @@ -65,18 +65,22 @@ type Mat4Positions = { function m4AsPositions(m: Mat4): Mat4Positions { return { + // row 0 m00 : m[0 * 4 + 0]!, m01 : m[0 * 4 + 1]!, m02 : m[0 * 4 + 2]!, m03 : m[0 * 4 + 3]!, + // row 1 m10 : m[1 * 4 + 0]!, m11 : m[1 * 4 + 1]!, m12 : m[1 * 4 + 2]!, m13 : m[1 * 4 + 3]!, + // row 2 m20 : m[2 * 4 + 0]!, m21 : m[2 * 4 + 1]!, m22 : m[2 * 4 + 2]!, m23 : m[2 * 4 + 3]!, + // row 3 m30 : m[3 * 4 + 0]!, m31 : m[3 * 4 + 1]!, m32 : m[3 * 4 + 2]!, @@ -84,6 +88,41 @@ function m4AsPositions(m: Mat4): Mat4Positions { } } +function m4FromPositions(p: Mat4Positions): Mat4 { + + const m: Mat4 = [ + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + ] + + // row 0 + m[0 * 4 + 0] = p.m00 + m[0 * 4 + 1] = p.m01 + m[0 * 4 + 2] = p.m02 + m[0 * 4 + 3] = p.m03 + // row 1 p. + m[1 * 4 + 0] = p.m10 + m[1 * 4 + 1] = p.m11 + m[1 * 4 + 2] = p.m12 + m[1 * 4 + 3] = p.m13 + // row 2 p. + m[2 * 4 + 0] = p.m20 + m[2 * 4 + 1] = p.m21 + m[2 * 4 + 2] = p.m22 + m[2 * 4 + 3] = p.m23 + // row 3 p. + m[3 * 4 + 0] = p.m30 + m[3 * 4 + 1] = p.m31 + m[3 * 4 + 2] = p.m32 + m[3 * 4 + 3] = p.m33 + + return m + + +} + export function m4lookAt(cameraPosition: Vec3, target: Vec3, up: Vec3): Mat4 { const zAxis = subtractVectors(cameraPosition, target) @@ -141,32 +180,88 @@ export function m4orthographic(left: number, right: number, bottom: number, top: ]; } - export function m4multiply(a: Mat4, b: Mat4): Mat4 { const ap = m4AsPositions(a); const bp = m4AsPositions(b); - return [ - bp.m00 * ap.m00 + bp.m01 * ap.m10 + bp.m02 * ap.m20 + bp.m03 * ap.m30, - bp.m00 * ap.m01 + bp.m01 * ap.m11 + bp.m02 * ap.m21 + bp.m03 * ap.m31, - bp.m00 * ap.m02 + bp.m01 * ap.m12 + bp.m02 * ap.m22 + bp.m03 * ap.m32, - bp.m00 * ap.m03 + bp.m01 * ap.m13 + bp.m02 * ap.m23 + bp.m03 * ap.m33, - bp.m10 * ap.m00 + bp.m11 * ap.m10 + bp.m12 * ap.m20 + bp.m13 * ap.m30, - bp.m10 * ap.m01 + bp.m11 * ap.m11 + bp.m12 * ap.m21 + bp.m13 * ap.m31, - bp.m10 * ap.m02 + bp.m11 * ap.m12 + bp.m12 * ap.m22 + bp.m13 * ap.m32, - bp.m10 * ap.m03 + bp.m11 * ap.m13 + bp.m12 * ap.m23 + bp.m13 * ap.m33, - bp.m20 * ap.m00 + bp.m21 * ap.m10 + bp.m22 * ap.m20 + bp.m23 * ap.m30, - bp.m20 * ap.m01 + bp.m21 * ap.m11 + bp.m22 * ap.m21 + bp.m23 * ap.m31, - bp.m20 * ap.m02 + bp.m21 * ap.m12 + bp.m22 * ap.m22 + bp.m23 * ap.m32, - bp.m20 * ap.m03 + bp.m21 * ap.m13 + bp.m22 * ap.m23 + bp.m23 * ap.m33, - bp.m30 * ap.m00 + bp.m31 * ap.m10 + bp.m32 * ap.m20 + bp.m33 * ap.m30, - bp.m30 * ap.m01 + bp.m31 * ap.m11 + bp.m32 * ap.m21 + bp.m33 * ap.m31, - bp.m30 * ap.m02 + bp.m31 * ap.m12 + bp.m32 * ap.m22 + bp.m33 * ap.m32, - bp.m30 * ap.m03 + bp.m31 * ap.m13 + bp.m32 * ap.m23 + bp.m33 * ap.m33, - ]; + const p: Mat4Positions = { + // row 0 + m00 : bp.m00 * ap.m00 + bp.m01 * ap.m10 + bp.m02 * ap.m20 + bp.m03 * ap.m30, + m01 : bp.m00 * ap.m01 + bp.m01 * ap.m11 + bp.m02 * ap.m21 + bp.m03 * ap.m31, + m02 : bp.m00 * ap.m02 + bp.m01 * ap.m12 + bp.m02 * ap.m22 + bp.m03 * ap.m32, + m03 : bp.m00 * ap.m03 + bp.m01 * ap.m13 + bp.m02 * ap.m23 + bp.m03 * ap.m33, + // row 1 + m10 : bp.m10 * ap.m00 + bp.m11 * ap.m10 + bp.m12 * ap.m20 + bp.m13 * ap.m30, + m11 : bp.m10 * ap.m01 + bp.m11 * ap.m11 + bp.m12 * ap.m21 + bp.m13 * ap.m31, + m12 : bp.m10 * ap.m02 + bp.m11 * ap.m12 + bp.m12 * ap.m22 + bp.m13 * ap.m32, + m13 : bp.m10 * ap.m03 + bp.m11 * ap.m13 + bp.m12 * ap.m23 + bp.m13 * ap.m33, + // row 2 + m20 : bp.m20 * ap.m00 + bp.m21 * ap.m10 + bp.m22 * ap.m20 + bp.m23 * ap.m30, + m21 : bp.m20 * ap.m01 + bp.m21 * ap.m11 + bp.m22 * ap.m21 + bp.m23 * ap.m31, + m22 : bp.m20 * ap.m02 + bp.m21 * ap.m12 + bp.m22 * ap.m22 + bp.m23 * ap.m32, + m23 : bp.m20 * ap.m03 + bp.m21 * ap.m13 + bp.m22 * ap.m23 + bp.m23 * ap.m33, + // row 3 + m30 : bp.m30 * ap.m00 + bp.m31 * ap.m10 + bp.m32 * ap.m20 + bp.m33 * ap.m30, + m31 : bp.m30 * ap.m01 + bp.m31 * ap.m11 + bp.m32 * ap.m21 + bp.m33 * ap.m31, + m32 : bp.m30 * ap.m02 + bp.m31 * ap.m12 + bp.m32 * ap.m22 + bp.m33 * ap.m32, + m33 : bp.m30 * ap.m03 + bp.m31 * ap.m13 + bp.m32 * ap.m23 + bp.m33 * ap.m33, + } + + return m4FromPositions(p) } +// export function m4multiply(a: Mat4, b: Mat4): Mat4 { + +// const ap = m4AsPositions(a); +// const bp = m4AsPositions(b); + +// return [ +// bp.m00 * ap.m00 + bp.m01 * ap.m10 + bp.m02 * ap.m20 + bp.m03 * ap.m30, +// bp.m00 * ap.m01 + bp.m01 * ap.m11 + bp.m02 * ap.m21 + bp.m03 * ap.m31, +// bp.m00 * ap.m02 + bp.m01 * ap.m12 + bp.m02 * ap.m22 + bp.m03 * ap.m32, +// bp.m00 * ap.m03 + bp.m01 * ap.m13 + bp.m02 * ap.m23 + bp.m03 * ap.m33, +// bp.m10 * ap.m00 + bp.m11 * ap.m10 + bp.m12 * ap.m20 + bp.m13 * ap.m30, +// bp.m10 * ap.m01 + bp.m11 * ap.m11 + bp.m12 * ap.m21 + bp.m13 * ap.m31, +// bp.m10 * ap.m02 + bp.m11 * ap.m12 + bp.m12 * ap.m22 + bp.m13 * ap.m32, +// bp.m10 * ap.m03 + bp.m11 * ap.m13 + bp.m12 * ap.m23 + bp.m13 * ap.m33, +// bp.m20 * ap.m00 + bp.m21 * ap.m10 + bp.m22 * ap.m20 + bp.m23 * ap.m30, +// bp.m20 * ap.m01 + bp.m21 * ap.m11 + bp.m22 * ap.m21 + bp.m23 * ap.m31, +// bp.m20 * ap.m02 + bp.m21 * ap.m12 + bp.m22 * ap.m22 + bp.m23 * ap.m32, +// bp.m20 * ap.m03 + bp.m21 * ap.m13 + bp.m22 * ap.m23 + bp.m23 * ap.m33, +// bp.m30 * ap.m00 + bp.m31 * ap.m10 + bp.m32 * ap.m20 + bp.m33 * ap.m30, +// bp.m30 * ap.m01 + bp.m31 * ap.m11 + bp.m32 * ap.m21 + bp.m33 * ap.m31, +// bp.m30 * ap.m02 + bp.m31 * ap.m12 + bp.m32 * ap.m22 + bp.m33 * ap.m32, +// bp.m30 * ap.m03 + bp.m31 * ap.m13 + bp.m32 * ap.m23 + bp.m33 * ap.m33, +// ]; +// } + +// export function m4Vec4multiply(m: Mat4, v: Vec4): Vec4 { + +// const mp = m4AsPositions(m); + + +// return [ +// // +// ap.m00 * bp.m00 + ap.m01 * bp.m10 + ap.m02 * bp.m20 + ap.m03 * bp.m30, +// ap.m00 * bp.m01 + ap.m01 * bp.m11 + ap.m02 * bp.m21 + ap.m03 * bp.m31, +// ap.m00 * bp.m02 + ap.m01 * bp.m12 + ap.m02 * bp.m22 + ap.m03 * bp.m32, +// ap.m00 * bp.m03 + ap.m01 * bp.m13 + ap.m02 * bp.m23 + ap.m03 * bp.m33, +// ap.m10 * bp.m00 + ap.m11 * bp.m10 + ap.m12 * bp.m20 + ap.m13 * bp.m30, +// ap.m10 * bp.m01 + ap.m11 * bp.m11 + ap.m12 * bp.m21 + ap.m13 * bp.m31, +// ap.m10 * bp.m02 + ap.m11 * bp.m12 + ap.m12 * bp.m22 + ap.m13 * bp.m32, +// ap.m10 * bp.m03 + ap.m11 * bp.m13 + ap.m12 * bp.m23 + ap.m13 * bp.m33, +// ap.m20 * bp.m00 + ap.m21 * bp.m10 + ap.m22 * bp.m20 + ap.m23 * bp.m30, +// ap.m20 * bp.m01 + ap.m21 * bp.m11 + ap.m22 * bp.m21 + ap.m23 * bp.m31, +// ap.m20 * bp.m02 + ap.m21 * bp.m12 + ap.m22 * bp.m22 + ap.m23 * bp.m32, +// ap.m20 * bp.m03 + ap.m21 * bp.m13 + ap.m22 * bp.m23 + ap.m23 * bp.m33, +// ap.m30 * bp.m00 + ap.m31 * bp.m10 + ap.m32 * bp.m20 + ap.m33 * bp.m30, +// ap.m30 * bp.m01 + ap.m31 * bp.m11 + ap.m32 * bp.m21 + ap.m33 * bp.m31, +// ap.m30 * bp.m02 + ap.m31 * bp.m12 + ap.m32 * bp.m22 + ap.m33 * bp.m32, +// ap.m30 * bp.m03 + ap.m31 * bp.m13 + ap.m32 * bp.m23 + ap.m33 * bp.m33, +// ]; +// } + export function m4translation(tx: number, ty: number, tz: number): Mat4Translation { return [ 1, 0, 0, 0, From 34eac30a35d94b3d0ec0c7d4f94530df641f6d70 Mon Sep 17 00:00:00 2001 From: Tom Greenwood Date: Tue, 6 Jan 2026 11:23:17 +0000 Subject: [PATCH 07/10] more-m4-change-mat --- demo-01-ts-webgl/lib/mat4.ts | 299 +++++++++++++++-------------------- 1 file changed, 131 insertions(+), 168 deletions(-) diff --git a/demo-01-ts-webgl/lib/mat4.ts b/demo-01-ts-webgl/lib/mat4.ts index 64e92ec..ae837ac 100644 --- a/demo-01-ts-webgl/lib/mat4.ts +++ b/demo-01-ts-webgl/lib/mat4.ts @@ -1,5 +1,4 @@ -import { Ray } from './raycast'; -import { Vec3, Vec4, subtractVectors, cross, vec3ToArray, vec4ToArray, normalize } from './vec' +import { Vec3, subtractVectors, cross, vec3ToArray, normalize } from './vec' export type Mat4 = [ @@ -44,51 +43,40 @@ export type Mat4ZRotation = [ 0, 0, 0, 1, ] -type Mat4Positions = { - m00: number - m01: number - m02: number - m03: number - m10: number - m11: number - m12: number - m13: number - m20: number - m21: number - m22: number - m23: number - m30: number - m31: number - m32: number - m33: number -} +type Row4 = [number, number, number, number] +type Mat4D = [ + Row4, Row4, Row4, Row4 +] -function m4AsPositions(m: Mat4): Mat4Positions { - return { - // row 0 - m00 : m[0 * 4 + 0]!, - m01 : m[0 * 4 + 1]!, - m02 : m[0 * 4 + 2]!, - m03 : m[0 * 4 + 3]!, - // row 1 - m10 : m[1 * 4 + 0]!, - m11 : m[1 * 4 + 1]!, - m12 : m[1 * 4 + 2]!, - m13 : m[1 * 4 + 3]!, - // row 2 - m20 : m[2 * 4 + 0]!, - m21 : m[2 * 4 + 1]!, - m22 : m[2 * 4 + 2]!, - m23 : m[2 * 4 + 3]!, - // row 3 - m30 : m[3 * 4 + 0]!, - m31 : m[3 * 4 + 1]!, - m32 : m[3 * 4 + 2]!, - m33 : m[3 * 4 + 3]!, - } +function m4AsPositions(m: Mat4): Mat4D { + return [ + + [m[0 * 4 + 0]!, + m[0 * 4 + 1]!, + m[0 * 4 + 2]!, + m[0 * 4 + 3]! + ], + + [m[1 * 4 + 0]!, + m[1 * 4 + 1]!, + m[1 * 4 + 2]!, + m[1 * 4 + 3]! + ], + + [m[2 * 4 + 0]!, + m[2 * 4 + 1]!, + m[2 * 4 + 2]!, + m[2 * 4 + 3]! + ], + [m[3 * 4 + 0]!, + m[3 * 4 + 1]!, + m[3 * 4 + 2]!, + m[3 * 4 + 3]! + ], + ] } -function m4FromPositions(p: Mat4Positions): Mat4 { +function m4FromPositions(p: Mat4D): Mat4 { const m: Mat4 = [ 0,0,0,0, @@ -97,26 +85,23 @@ function m4FromPositions(p: Mat4Positions): Mat4 { 0,0,0,0, ] - // row 0 - m[0 * 4 + 0] = p.m00 - m[0 * 4 + 1] = p.m01 - m[0 * 4 + 2] = p.m02 - m[0 * 4 + 3] = p.m03 - // row 1 p. - m[1 * 4 + 0] = p.m10 - m[1 * 4 + 1] = p.m11 - m[1 * 4 + 2] = p.m12 - m[1 * 4 + 3] = p.m13 - // row 2 p. - m[2 * 4 + 0] = p.m20 - m[2 * 4 + 1] = p.m21 - m[2 * 4 + 2] = p.m22 - m[2 * 4 + 3] = p.m23 - // row 3 p. - m[3 * 4 + 0] = p.m30 - m[3 * 4 + 1] = p.m31 - m[3 * 4 + 2] = p.m32 - m[3 * 4 + 3] = p.m33 + + m[0 * 4 + 0] = p[0][0] + m[0 * 4 + 1] = p[0][1] + m[0 * 4 + 2] = p[0][2] + m[0 * 4 + 3] = p[0][3] + m[1 * 4 + 0] = p[1][0] + m[1 * 4 + 1] = p[1][1] + m[1 * 4 + 2] = p[1][2] + m[1 * 4 + 3] = p[1][3] + m[2 * 4 + 0] = p[2][0] + m[2 * 4 + 1] = p[2][1] + m[2 * 4 + 2] = p[2][2] + m[2 * 4 + 3] = p[2][3] + m[3 * 4 + 0] = p[3][0] + m[3 * 4 + 1] = p[3][1] + m[3 * 4 + 2] = p[3][2] + m[3 * 4 + 3] = p[3][3] return m @@ -185,56 +170,34 @@ export function m4multiply(a: Mat4, b: Mat4): Mat4 { const ap = m4AsPositions(a); const bp = m4AsPositions(b); - const p: Mat4Positions = { - // row 0 - m00 : bp.m00 * ap.m00 + bp.m01 * ap.m10 + bp.m02 * ap.m20 + bp.m03 * ap.m30, - m01 : bp.m00 * ap.m01 + bp.m01 * ap.m11 + bp.m02 * ap.m21 + bp.m03 * ap.m31, - m02 : bp.m00 * ap.m02 + bp.m01 * ap.m12 + bp.m02 * ap.m22 + bp.m03 * ap.m32, - m03 : bp.m00 * ap.m03 + bp.m01 * ap.m13 + bp.m02 * ap.m23 + bp.m03 * ap.m33, - // row 1 - m10 : bp.m10 * ap.m00 + bp.m11 * ap.m10 + bp.m12 * ap.m20 + bp.m13 * ap.m30, - m11 : bp.m10 * ap.m01 + bp.m11 * ap.m11 + bp.m12 * ap.m21 + bp.m13 * ap.m31, - m12 : bp.m10 * ap.m02 + bp.m11 * ap.m12 + bp.m12 * ap.m22 + bp.m13 * ap.m32, - m13 : bp.m10 * ap.m03 + bp.m11 * ap.m13 + bp.m12 * ap.m23 + bp.m13 * ap.m33, - // row 2 - m20 : bp.m20 * ap.m00 + bp.m21 * ap.m10 + bp.m22 * ap.m20 + bp.m23 * ap.m30, - m21 : bp.m20 * ap.m01 + bp.m21 * ap.m11 + bp.m22 * ap.m21 + bp.m23 * ap.m31, - m22 : bp.m20 * ap.m02 + bp.m21 * ap.m12 + bp.m22 * ap.m22 + bp.m23 * ap.m32, - m23 : bp.m20 * ap.m03 + bp.m21 * ap.m13 + bp.m22 * ap.m23 + bp.m23 * ap.m33, - // row 3 - m30 : bp.m30 * ap.m00 + bp.m31 * ap.m10 + bp.m32 * ap.m20 + bp.m33 * ap.m30, - m31 : bp.m30 * ap.m01 + bp.m31 * ap.m11 + bp.m32 * ap.m21 + bp.m33 * ap.m31, - m32 : bp.m30 * ap.m02 + bp.m31 * ap.m12 + bp.m32 * ap.m22 + bp.m33 * ap.m32, - m33 : bp.m30 * ap.m03 + bp.m31 * ap.m13 + bp.m32 * ap.m23 + bp.m33 * ap.m33, - } + const p: Mat4D = [ + + [bp[0][0] * ap[0][0] + bp[0][1] * ap[1][0] + bp[0][2] * ap[2][0] + bp[0][3] * ap[3][0], + bp[0][0] * ap[0][1] + bp[0][1] * ap[1][1] + bp[0][2] * ap[2][1] + bp[0][3] * ap[3][1], + bp[0][0] * ap[0][2] + bp[0][1] * ap[1][2] + bp[0][2] * ap[2][2] + bp[0][3] * ap[3][2], + bp[0][0] * ap[0][3] + bp[0][1] * ap[1][3] + bp[0][2] * ap[2][3] + bp[0][3] * ap[3][3], + ], + [bp[1][0] * ap[0][0] + bp[1][1] * ap[1][0] + bp[1][2] * ap[2][0] + bp[1][3] * ap[3][0], + bp[1][0] * ap[0][1] + bp[1][1] * ap[1][1] + bp[1][2] * ap[2][1] + bp[1][3] * ap[3][1], + bp[1][0] * ap[0][2] + bp[1][1] * ap[1][2] + bp[1][2] * ap[2][2] + bp[1][3] * ap[3][2], + bp[1][0] * ap[0][3] + bp[1][1] * ap[1][3] + bp[1][2] * ap[2][3] + bp[1][3] * ap[3][3], + ], + [bp[2][0] * ap[0][0] + bp[2][1] * ap[1][0] + bp[2][2] * ap[2][0] + bp[2][3] * ap[3][0], + bp[2][0] * ap[0][1] + bp[2][1] * ap[1][1] + bp[2][2] * ap[2][1] + bp[2][3] * ap[3][1], + bp[2][0] * ap[0][2] + bp[2][1] * ap[1][2] + bp[2][2] * ap[2][2] + bp[2][3] * ap[3][2], + bp[2][0] * ap[0][3] + bp[2][1] * ap[1][3] + bp[2][2] * ap[2][3] + bp[2][3] * ap[3][3], + ], + [bp[3][0] * ap[0][0] + bp[3][1] * ap[1][0] + bp[3][2] * ap[2][0] + bp[3][3] * ap[3][0], + bp[3][0] * ap[0][1] + bp[3][1] * ap[1][1] + bp[3][2] * ap[2][1] + bp[3][3] * ap[3][1], + bp[3][0] * ap[0][2] + bp[3][1] * ap[1][2] + bp[3][2] * ap[2][2] + bp[3][3] * ap[3][2], + bp[3][0] * ap[0][3] + bp[3][1] * ap[1][3] + bp[3][2] * ap[2][3] + bp[3][3] * ap[3][3], + ] + ] return m4FromPositions(p) } -// export function m4multiply(a: Mat4, b: Mat4): Mat4 { -// const ap = m4AsPositions(a); -// const bp = m4AsPositions(b); - -// return [ -// bp.m00 * ap.m00 + bp.m01 * ap.m10 + bp.m02 * ap.m20 + bp.m03 * ap.m30, -// bp.m00 * ap.m01 + bp.m01 * ap.m11 + bp.m02 * ap.m21 + bp.m03 * ap.m31, -// bp.m00 * ap.m02 + bp.m01 * ap.m12 + bp.m02 * ap.m22 + bp.m03 * ap.m32, -// bp.m00 * ap.m03 + bp.m01 * ap.m13 + bp.m02 * ap.m23 + bp.m03 * ap.m33, -// bp.m10 * ap.m00 + bp.m11 * ap.m10 + bp.m12 * ap.m20 + bp.m13 * ap.m30, -// bp.m10 * ap.m01 + bp.m11 * ap.m11 + bp.m12 * ap.m21 + bp.m13 * ap.m31, -// bp.m10 * ap.m02 + bp.m11 * ap.m12 + bp.m12 * ap.m22 + bp.m13 * ap.m32, -// bp.m10 * ap.m03 + bp.m11 * ap.m13 + bp.m12 * ap.m23 + bp.m13 * ap.m33, -// bp.m20 * ap.m00 + bp.m21 * ap.m10 + bp.m22 * ap.m20 + bp.m23 * ap.m30, -// bp.m20 * ap.m01 + bp.m21 * ap.m11 + bp.m22 * ap.m21 + bp.m23 * ap.m31, -// bp.m20 * ap.m02 + bp.m21 * ap.m12 + bp.m22 * ap.m22 + bp.m23 * ap.m32, -// bp.m20 * ap.m03 + bp.m21 * ap.m13 + bp.m22 * ap.m23 + bp.m23 * ap.m33, -// bp.m30 * ap.m00 + bp.m31 * ap.m10 + bp.m32 * ap.m20 + bp.m33 * ap.m30, -// bp.m30 * ap.m01 + bp.m31 * ap.m11 + bp.m32 * ap.m21 + bp.m33 * ap.m31, -// bp.m30 * ap.m02 + bp.m31 * ap.m12 + bp.m32 * ap.m22 + bp.m33 * ap.m32, -// bp.m30 * ap.m03 + bp.m31 * ap.m13 + bp.m32 * ap.m23 + bp.m33 * ap.m33, -// ]; -// } // export function m4Vec4multiply(m: Mat4, v: Vec4): Vec4 { @@ -374,71 +337,71 @@ export function m4transpose(m: Mat4) { export function m4inverse(m: Mat4): Mat4 { const p = m4AsPositions(m) - const tmp_0 = p.m22 * p.m33; - const tmp_1 = p.m32 * p.m23; - const tmp_2 = p.m12 * p.m33; - const tmp_3 = p.m32 * p.m13; - const tmp_4 = p.m12 * p.m23; - const tmp_5 = p.m22 * p.m13; - const tmp_6 = p.m02 * p.m33; - const tmp_7 = p.m32 * p.m03; - const tmp_8 = p.m02 * p.m23; - const tmp_9 = p.m22 * p.m03; - const tmp_10 = p.m02 * p.m13; - const tmp_11 = p.m12 * p.m03; - const tmp_12 = p.m20 * p.m31; - const tmp_13 = p.m30 * p.m21; - const tmp_14 = p.m10 * p.m31; - const tmp_15 = p.m30 * p.m11; - const tmp_16 = p.m10 * p.m21; - const tmp_17 = p.m20 * p.m11; - const tmp_18 = p.m00 * p.m31; - const tmp_19 = p.m30 * p.m01; - const tmp_20 = p.m00 * p.m21; - const tmp_21 = p.m20 * p.m01; - const tmp_22 = p.m00 * p.m11; - const tmp_23 = p.m10 * p.m01; - - const t0 = (tmp_0 * p.m11 + tmp_3 * p.m21 + tmp_4 * p.m31) - - (tmp_1 * p.m11 + tmp_2 * p.m21 + tmp_5 * p.m31); - const t1 = (tmp_1 * p.m01 + tmp_6 * p.m21 + tmp_9 * p.m31) - - (tmp_0 * p.m01 + tmp_7 * p.m21 + tmp_8 * p.m31); - const t2 = (tmp_2 * p.m01 + tmp_7 * p.m11 + tmp_10 * p.m31) - - (tmp_3 * p.m01 + tmp_6 * p.m11 + tmp_11 * p.m31); - const t3 = (tmp_5 * p.m01 + tmp_8 * p.m11 + tmp_11 * p.m21) - - (tmp_4 * p.m01 + tmp_9 * p.m11 + tmp_10 * p.m21); - - const d = 1.0 / (p.m00 * t0 + p.m10 * t1 + p.m20 * t2 + p.m30 * t3); + const tmp_0 = p[2][2] * p[3][3]; + const tmp_1 = p[3][2] * p[2][3]; + const tmp_2 = p[1][2] * p[3][3]; + const tmp_3 = p[3][2] * p[1][3]; + const tmp_4 = p[1][2] * p[2][3]; + const tmp_5 = p[2][2] * p[1][3]; + const tmp_6 = p[0][2] * p[3][3]; + const tmp_7 = p[3][2] * p[0][3]; + const tmp_8 = p[0][2] * p[2][3]; + const tmp_9 = p[2][2] * p[0][3]; + const tmp_10 = p[0][2] * p[1][3]; + const tmp_11 = p[1][2] * p[0][3]; + const tmp_12 = p[2][0] * p[3][1]; + const tmp_13 = p[3][0] * p[2][1]; + const tmp_14 = p[1][0] * p[3][1]; + const tmp_15 = p[3][0] * p[1][1]; + const tmp_16 = p[1][0] * p[2][1]; + const tmp_17 = p[2][0] * p[1][1]; + const tmp_18 = p[0][0] * p[3][1]; + const tmp_19 = p[3][0] * p[0][1]; + const tmp_20 = p[0][0] * p[2][1]; + const tmp_21 = p[2][0] * p[0][1]; + const tmp_22 = p[0][0] * p[1][1]; + const tmp_23 = p[1][0] * p[0][1]; + + const t0 = (tmp_0 * p[1][1] + tmp_3 * p[2][1] + tmp_4 * p[3][1]) - + (tmp_1 * p[1][1] + tmp_2 * p[2][1] + tmp_5 * p[3][1]); + const t1 = (tmp_1 * p[0][1] + tmp_6 * p[2][1] + tmp_9 * p[3][1]) - + (tmp_0 * p[0][1] + tmp_7 * p[2][1] + tmp_8 * p[3][1]); + const t2 = (tmp_2 * p[0][1] + tmp_7 * p[1][1] + tmp_10 * p[3][1]) - + (tmp_3 * p[0][1] + tmp_6 * p[1][1] + tmp_11 * p[3][1]); + const t3 = (tmp_5 * p[0][1] + tmp_8 * p[1][1] + tmp_11 * p[2][1]) - + (tmp_4 * p[0][1] + tmp_9 * p[1][1] + tmp_10 * p[2][1]); + + const d = 1.0 / (p[0][0] * t0 + p[1][0] * t1 + p[2][0] * t2 + p[3][0] * t3); return [ d * t0, d * t1, d * t2, d * t3, - d * ((tmp_1 * p.m10 + tmp_2 * p.m20 + tmp_5 * p.m30) - - (tmp_0 * p.m10 + tmp_3 * p.m20 + tmp_4 * p.m30)), - d * ((tmp_0 * p.m00 + tmp_7 * p.m20 + tmp_8 * p.m30) - - (tmp_1 * p.m00 + tmp_6 * p.m20 + tmp_9 * p.m30)), - d * ((tmp_3 * p.m00 + tmp_6 * p.m10 + tmp_11 * p.m30) - - (tmp_2 * p.m00 + tmp_7 * p.m10 + tmp_10 * p.m30)), - d * ((tmp_4 * p.m00 + tmp_9 * p.m10 + tmp_10 * p.m20) - - (tmp_5 * p.m00 + tmp_8 * p.m10 + tmp_11 * p.m20)), - d * ((tmp_12 * p.m13 + tmp_15 * p.m23 + tmp_16 * p.m33) - - (tmp_13 * p.m13 + tmp_14 * p.m23 + tmp_17 * p.m33)), - d * ((tmp_13 * p.m03 + tmp_18 * p.m23 + tmp_21 * p.m33) - - (tmp_12 * p.m03 + tmp_19 * p.m23 + tmp_20 * p.m33)), - d * ((tmp_14 * p.m03 + tmp_19 * p.m13 + tmp_22 * p.m33) - - (tmp_15 * p.m03 + tmp_18 * p.m13 + tmp_23 * p.m33)), - d * ((tmp_17 * p.m03 + tmp_20 * p.m13 + tmp_23 * p.m23) - - (tmp_16 * p.m03 + tmp_21 * p.m13 + tmp_22 * p.m23)), - d * ((tmp_14 * p.m22 + tmp_17 * p.m32 + tmp_13 * p.m12) - - (tmp_16 * p.m32 + tmp_12 * p.m12 + tmp_15 * p.m22)), - d * ((tmp_20 * p.m32 + tmp_12 * p.m02 + tmp_19 * p.m22) - - (tmp_18 * p.m22 + tmp_21 * p.m32 + tmp_13 * p.m02)), - d * ((tmp_18 * p.m12 + tmp_23 * p.m32 + tmp_15 * p.m02) - - (tmp_22 * p.m32 + tmp_14 * p.m02 + tmp_19 * p.m12)), - d * ((tmp_22 * p.m22 + tmp_16 * p.m02 + tmp_21 * p.m12) - - (tmp_20 * p.m12 + tmp_23 * p.m22 + tmp_17 * p.m02)) + d * ((tmp_1 * p[1][0] + tmp_2 * p[2][0] + tmp_5 * p[3][0]) - + (tmp_0 * p[1][0] + tmp_3 * p[2][0] + tmp_4 * p[3][0])), + d * ((tmp_0 * p[0][0] + tmp_7 * p[2][0] + tmp_8 * p[3][0]) - + (tmp_1 * p[0][0] + tmp_6 * p[2][0] + tmp_9 * p[3][0])), + d * ((tmp_3 * p[0][0] + tmp_6 * p[1][0] + tmp_11 * p[3][0]) - + (tmp_2 * p[0][0] + tmp_7 * p[1][0] + tmp_10 * p[3][0])), + d * ((tmp_4 * p[0][0] + tmp_9 * p[1][0] + tmp_10 * p[2][0]) - + (tmp_5 * p[0][0] + tmp_8 * p[1][0] + tmp_11 * p[2][0])), + d * ((tmp_12 * p[1][3] + tmp_15 * p[2][3] + tmp_16 * p[3][3]) - + (tmp_13 * p[1][3] + tmp_14 * p[2][3] + tmp_17 * p[3][3])), + d * ((tmp_13 * p[0][3] + tmp_18 * p[2][3] + tmp_21 * p[3][3]) - + (tmp_12 * p[0][3] + tmp_19 * p[2][3] + tmp_20 * p[3][3])), + d * ((tmp_14 * p[0][3] + tmp_19 * p[1][3] + tmp_22 * p[3][3]) - + (tmp_15 * p[0][3] + tmp_18 * p[1][3] + tmp_23 * p[3][3])), + d * ((tmp_17 * p[0][3] + tmp_20 * p[1][3] + tmp_23 * p[2][3]) - + (tmp_16 * p[0][3] + tmp_21 * p[1][3] + tmp_22 * p[2][3])), + d * ((tmp_14 * p[2][2] + tmp_17 * p[3][2] + tmp_13 * p[1][2]) - + (tmp_16 * p[3][2] + tmp_12 * p[1][2] + tmp_15 * p[2][2])), + d * ((tmp_20 * p[3][2] + tmp_12 * p[0][2] + tmp_19 * p[2][2]) - + (tmp_18 * p[2][2] + tmp_21 * p[3][2] + tmp_13 * p[0][2])), + d * ((tmp_18 * p[1][2] + tmp_23 * p[3][2] + tmp_15 * p[0][2]) - + (tmp_22 * p[3][2] + tmp_14 * p[0][2] + tmp_19 * p[1][2])), + d * ((tmp_22 * p[2][2] + tmp_16 * p[0][2] + tmp_21 * p[1][2]) - + (tmp_20 * p[1][2] + tmp_23 * p[2][2] + tmp_17 * p[0][2])) ]; } From 69a75c562c8c96ed8e9885e54f63c3679df2ca5b Mon Sep 17 00:00:00 2001 From: Tom Greenwood Date: Tue, 6 Jan 2026 11:34:58 +0000 Subject: [PATCH 08/10] more-m4-change-partialvecmultiply --- demo-01-ts-webgl/lib/mat4.ts | 54 ++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/demo-01-ts-webgl/lib/mat4.ts b/demo-01-ts-webgl/lib/mat4.ts index ae837ac..19f3b5b 100644 --- a/demo-01-ts-webgl/lib/mat4.ts +++ b/demo-01-ts-webgl/lib/mat4.ts @@ -1,4 +1,4 @@ -import { Vec3, subtractVectors, cross, vec3ToArray, normalize } from './vec' +import { Vec3, subtractVectors, cross, vec3ToArray, normalize, Vec4 } from './vec' export type Mat4 = [ @@ -199,31 +199,21 @@ export function m4multiply(a: Mat4, b: Mat4): Mat4 { -// export function m4Vec4multiply(m: Mat4, v: Vec4): Vec4 { +export function m4Vec4multiply(m: Mat4, v: Vec4): Vec4 { -// const mp = m4AsPositions(m); - + const mp = m4AsPositions(m); -// return [ -// // -// ap.m00 * bp.m00 + ap.m01 * bp.m10 + ap.m02 * bp.m20 + ap.m03 * bp.m30, -// ap.m00 * bp.m01 + ap.m01 * bp.m11 + ap.m02 * bp.m21 + ap.m03 * bp.m31, -// ap.m00 * bp.m02 + ap.m01 * bp.m12 + ap.m02 * bp.m22 + ap.m03 * bp.m32, -// ap.m00 * bp.m03 + ap.m01 * bp.m13 + ap.m02 * bp.m23 + ap.m03 * bp.m33, -// ap.m10 * bp.m00 + ap.m11 * bp.m10 + ap.m12 * bp.m20 + ap.m13 * bp.m30, -// ap.m10 * bp.m01 + ap.m11 * bp.m11 + ap.m12 * bp.m21 + ap.m13 * bp.m31, -// ap.m10 * bp.m02 + ap.m11 * bp.m12 + ap.m12 * bp.m22 + ap.m13 * bp.m32, -// ap.m10 * bp.m03 + ap.m11 * bp.m13 + ap.m12 * bp.m23 + ap.m13 * bp.m33, -// ap.m20 * bp.m00 + ap.m21 * bp.m10 + ap.m22 * bp.m20 + ap.m23 * bp.m30, -// ap.m20 * bp.m01 + ap.m21 * bp.m11 + ap.m22 * bp.m21 + ap.m23 * bp.m31, -// ap.m20 * bp.m02 + ap.m21 * bp.m12 + ap.m22 * bp.m22 + ap.m23 * bp.m32, -// ap.m20 * bp.m03 + ap.m21 * bp.m13 + ap.m22 * bp.m23 + ap.m23 * bp.m33, -// ap.m30 * bp.m00 + ap.m31 * bp.m10 + ap.m32 * bp.m20 + ap.m33 * bp.m30, -// ap.m30 * bp.m01 + ap.m31 * bp.m11 + ap.m32 * bp.m21 + ap.m33 * bp.m31, -// ap.m30 * bp.m02 + ap.m31 * bp.m12 + ap.m32 * bp.m22 + ap.m33 * bp.m32, -// ap.m30 * bp.m03 + ap.m31 * bp.m13 + ap.m32 * bp.m23 + ap.m33 * bp.m33, -// ]; -// } + const p: Vec4 = { + + x: mp[0][0] * v.x + mp[0][1] * v.x + mp[0][2] * v.x + mp[0][3] * v.x, + y: mp[1][0] * v.y + mp[1][1] * v.y + mp[1][2] * v.y + mp[1][3] * v.y, + z: mp[2][0] * v.z + mp[2][1] * v.z + mp[2][2] * v.z + mp[2][3] * v.z, + w: mp[3][0] * v.w + mp[3][1] * v.w + mp[3][2] * v.w + mp[3][3] * v.w, + + } + + return p + } export function m4translation(tx: number, ty: number, tz: number): Mat4Translation { return [ @@ -405,6 +395,22 @@ export function m4inverse(m: Mat4): Mat4 { ]; } +// export function m4PositionMultiply(v: Vec3, m: Mat4): Vec3 { + +// const v4 = {...v, w: 1} +// const dst = m4Vec4multiply(m, v4) + +// return {x: dst.x/dst.w, y: dst.y/dst.w, z: dst.z/dst.w } +// } + +// export function m4DirectionMultiply(v: Vec3, m: Mat4): Vec3 { + +// const v4 = {...v, w: 0} +// const dst = m4Vec4multiply(m, v4) + +// return { x: dst.x, y: dst.y, z: dst.z }; + +// } export function m4PositionMultiply(v: Vec3, m: Mat4): Vec3 { From 7e19a47bf1feb98aa7ae28da4534619324f6685b Mon Sep 17 00:00:00 2001 From: Tom Greenwood Date: Tue, 6 Jan 2026 11:58:16 +0000 Subject: [PATCH 09/10] m4vec4multiply complete --- demo-01-ts-webgl/lib/mat4.ts | 69 +++++++++++------------------------- 1 file changed, 21 insertions(+), 48 deletions(-) diff --git a/demo-01-ts-webgl/lib/mat4.ts b/demo-01-ts-webgl/lib/mat4.ts index 19f3b5b..2844ab7 100644 --- a/demo-01-ts-webgl/lib/mat4.ts +++ b/demo-01-ts-webgl/lib/mat4.ts @@ -1,4 +1,4 @@ -import { Vec3, subtractVectors, cross, vec3ToArray, normalize, Vec4 } from './vec' +import { Vec3, subtractVectors, cross, vec3ToArray, normalize, Vec4, vec4ToArray } from './vec' export type Mat4 = [ @@ -199,21 +199,7 @@ export function m4multiply(a: Mat4, b: Mat4): Mat4 { -export function m4Vec4multiply(m: Mat4, v: Vec4): Vec4 { - - const mp = m4AsPositions(m); - - const p: Vec4 = { - - x: mp[0][0] * v.x + mp[0][1] * v.x + mp[0][2] * v.x + mp[0][3] * v.x, - y: mp[1][0] * v.y + mp[1][1] * v.y + mp[1][2] * v.y + mp[1][3] * v.y, - z: mp[2][0] * v.z + mp[2][1] * v.z + mp[2][2] * v.z + mp[2][3] * v.z, - w: mp[3][0] * v.w + mp[3][1] * v.w + mp[3][2] * v.w + mp[3][3] * v.w, - - } - return p - } export function m4translation(tx: number, ty: number, tz: number): Mat4Translation { return [ @@ -395,50 +381,37 @@ export function m4inverse(m: Mat4): Mat4 { ]; } -// export function m4PositionMultiply(v: Vec3, m: Mat4): Vec3 { - -// const v4 = {...v, w: 1} -// const dst = m4Vec4multiply(m, v4) -// return {x: dst.x/dst.w, y: dst.y/dst.w, z: dst.z/dst.w } -// } +export function m4Vec4multiply(m: Mat4, v: Vec4): Vec4 { -// export function m4DirectionMultiply(v: Vec3, m: Mat4): Vec3 { - -// const v4 = {...v, w: 0} -// const dst = m4Vec4multiply(m, v4) + const mm = m4AsPositions(m) -// return { x: dst.x, y: dst.y, z: dst.z }; + return { + x: v.x * mm[0][0] + v.y * mm[1][0]! + v.z * mm[2][0]! + v.w * mm[3][0]!, + y: v.x * mm[0][1] + v.y * mm[1][1]! + v.z * mm[2][1]! + v.w * mm[3][1]!, + z: v.x * mm[0][2] + v.y * mm[1][2]! + v.z * mm[2][2]! + v.w * mm[3][2]!, + w: v.x * mm[0][3] + v.y * mm[1][3]! + v.z * mm[2][3]! + v.w * mm[3][3]! + + } + } -// } export function m4PositionMultiply(v: Vec3, m: Mat4): Vec3 { - - const vArray: [number, number, number, number ] = [...vec3ToArray(v), 1] - const dst: [number, number, number, number] = [0,0,0,0]; - for (let i = 0; i < 4; ++i) { - for (let j = 0; j < 4; ++j) { - dst[i]! += vArray[j]! * m[j * 4 + i]!; // ts is not smart enough to see that we set dst[i] to a number already - } - } + + const v4 = {...v, w: 1} + const dst = m4Vec4multiply(m, v4) - return {x: dst[0]/dst[3], y: dst[1]/dst[3], z: dst[2]/dst[3] } - } + return {x: dst.x/dst.w, y: dst.y/dst.w, z: dst.z/dst.w } +} export function m4DirectionMultiply(v: Vec3, m: Mat4): Vec3 { - - const vArray: [number, number, number, number ] = [...vec3ToArray(v), 0] - const dst: [number, number, number, number] = [0,0,0,0]; - for (let i = 0; i < 4; ++i) { - for (let j = 0; j < 4; ++j) { - dst[i]! += vArray[j]! * m[j * 4 + i]!; // ts is not smart enough to see that we set dst[i] to a number already - } - } + + const v4 = {...v, w: 0} + const dst = m4Vec4multiply(m, v4) - return { x: dst[0], y: dst[1], z: dst[2] }; - - } + return { x: dst.x, y: dst.y, z: dst.z }; +} export function m4fromPositionAndEuler(position: Vec3, euler: Vec3): Mat4 { From d7d6d83607f7718ff082b3d417016d5305b7ce4e Mon Sep 17 00:00:00 2001 From: Tom Greenwood Date: Tue, 6 Jan 2026 12:32:16 +0000 Subject: [PATCH 10/10] full replace mat4 type --- demo-01-ts-webgl/lib/BasicRenderProgram.ts | 14 +- demo-01-ts-webgl/lib/mat4.ts | 448 ++++++++++----------- 2 files changed, 213 insertions(+), 249 deletions(-) diff --git a/demo-01-ts-webgl/lib/BasicRenderProgram.ts b/demo-01-ts-webgl/lib/BasicRenderProgram.ts index cc28248..c3349e3 100644 --- a/demo-01-ts-webgl/lib/BasicRenderProgram.ts +++ b/demo-01-ts-webgl/lib/BasicRenderProgram.ts @@ -1,6 +1,6 @@ import { AttributeBinding, createProgramFromRaw } from "./shaderUtils" import { AmbientLight, DirectionalLight, PointLight } from "./light"; -import { m4fromPositionAndEuler, m4inverse, m4multiply, m4orthographic, m4perspective, m4PositionMultiply, m4xRotation, Mat4 } from "./mat4"; +import { m4fromPositionAndEuler, m4inverse, m4multiply, m4orthographic, m4perspective, m4PositionMultiply, m4ToArray, m4xRotation, Mat4 } from "./mat4"; import { Camera } from "./camera"; import { InputState } from "./input"; @@ -103,9 +103,9 @@ export function updateUniforms( camera.aspect, camera.near, camera.far) - gl.uniformMatrix4fv(renderProgram.worldMatrixUniformLocation, false, shapeWorld); - gl.uniformMatrix4fv(renderProgram.viewUniformLocation, false, viewMatrix); - gl.uniformMatrix4fv(renderProgram.projectionUniformLocation, false, projectionMatrix); + gl.uniformMatrix4fv(renderProgram.worldMatrixUniformLocation, false, m4ToArray(shapeWorld)); + gl.uniformMatrix4fv(renderProgram.viewUniformLocation, false, m4ToArray(viewMatrix)); + gl.uniformMatrix4fv(renderProgram.projectionUniformLocation, false, m4ToArray(projectionMatrix)); // update material uniforms gl.uniform3fv(renderProgram.materialUniform.colorLocation, colorToArray(mesh.material.color)); @@ -122,7 +122,7 @@ export function updateUniforms( // shadows // shadow map must be bound - gl.uniformMatrix4fv(renderProgram.shadowUniform.lightViewLocation, false, lightViewProjectionMatrix); + gl.uniformMatrix4fv(renderProgram.shadowUniform.lightViewLocation, false, m4ToArray(lightViewProjectionMatrix)); // set point light @@ -585,8 +585,8 @@ export function drawShadowScene( const drawInitializedMesh = (mesh: Mesh) => { const vao = glState.vaos.get(mesh._id!)!; gl.bindVertexArray(vao); - gl.uniformMatrix4fv(shadowProgram.u_model, false, node._worldTransform); - gl.uniformMatrix4fv(shadowProgram.u_lightViewProj, false, lightViewProj); + gl.uniformMatrix4fv(shadowProgram.u_model, false, m4ToArray(node._worldTransform)); + gl.uniformMatrix4fv(shadowProgram.u_lightViewProj, false, m4ToArray(lightViewProj)); if (mesh.vertices.indices) { gl.drawElements(gl.TRIANGLES, mesh.vertices.indices.length, gl.UNSIGNED_SHORT, 0); } else { diff --git a/demo-01-ts-webgl/lib/mat4.ts b/demo-01-ts-webgl/lib/mat4.ts index 2844ab7..ca71f57 100644 --- a/demo-01-ts-webgl/lib/mat4.ts +++ b/demo-01-ts-webgl/lib/mat4.ts @@ -1,7 +1,7 @@ -import { Vec3, subtractVectors, cross, vec3ToArray, normalize, Vec4, vec4ToArray } from './vec' +import { Vec3, subtractVectors, cross, normalize, Vec4 } from './vec' -export type Mat4 = [ +export type Mat4Array = [ number, number, number, number, number, number, number, number, number, number, number, number, @@ -9,103 +9,75 @@ export type Mat4 = [ ] export type Mat4Scaling = [ - number, 0, 0, 0, - 0, number, 0, 0, - 0, 0, number, 0, - 0, 0, 0, 1, + [number, 0, 0, 0], + [0, number, 0, 0], + [0, 0, number, 0], + [0, 0, 0, 1] ] export type Mat4Translation = [ - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - number, number, number, 1, + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [number, number, number, 1] ] export type Mat4XRotation = [ - 1, 0, 0, 0, - 0, number, number, 0, - 0, number, number, 0, - 0, 0, 0, 1, + [1, 0, 0, 0], + [0, number, number, 0], + [0, number, number, 0], + [0, 0, 0, 1], ] export type Mat4YRotation = [ - number, 0, number, 0, - 0, 1, 0, 0, - number, 0, number, 0, - 0, 0, 0, 1, + [number, 0, number, 0], + [0, 1, 0, 0], + [number, 0, number, 0], + [0, 0, 0, 1], ] export type Mat4ZRotation = [ - number, number, 0, 0, - number, number, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1, + [number, number, 0, 0], + [number, number, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, 1], ] -type Row4 = [number, number, number, number] -type Mat4D = [ - Row4, Row4, Row4, Row4 +export type Mat4 = [ + [number, number, number, number], + [number, number, number, number], + [number, number, number, number], + [number, number, number, number] ] -function m4AsPositions(m: Mat4): Mat4D { - return [ - - [m[0 * 4 + 0]!, - m[0 * 4 + 1]!, - m[0 * 4 + 2]!, - m[0 * 4 + 3]! - ], - - [m[1 * 4 + 0]!, - m[1 * 4 + 1]!, - m[1 * 4 + 2]!, - m[1 * 4 + 3]! - ], - - [m[2 * 4 + 0]!, - m[2 * 4 + 1]!, - m[2 * 4 + 2]!, - m[2 * 4 + 3]! - ], - [m[3 * 4 + 0]!, - m[3 * 4 + 1]!, - m[3 * 4 + 2]!, - m[3 * 4 + 3]! - ], - ] -} - -function m4FromPositions(p: Mat4D): Mat4 { +export function m4ToArray(p: Mat4): Mat4Array { - const m: Mat4 = [ + const m: Mat4Array = [ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, ] - - - m[0 * 4 + 0] = p[0][0] - m[0 * 4 + 1] = p[0][1] - m[0 * 4 + 2] = p[0][2] - m[0 * 4 + 3] = p[0][3] - m[1 * 4 + 0] = p[1][0] - m[1 * 4 + 1] = p[1][1] - m[1 * 4 + 2] = p[1][2] - m[1 * 4 + 3] = p[1][3] - m[2 * 4 + 0] = p[2][0] - m[2 * 4 + 1] = p[2][1] - m[2 * 4 + 2] = p[2][2] - m[2 * 4 + 3] = p[2][3] - m[3 * 4 + 0] = p[3][0] - m[3 * 4 + 1] = p[3][1] - m[3 * 4 + 2] = p[3][2] - m[3 * 4 + 3] = p[3][3] + + m[0] = p[0][0] + m[1] = p[0][1] + m[2] = p[0][2] + m[3] = p[0][3] + m[4] = p[1][0] + m[5] = p[1][1] + m[6] = p[1][2] + m[7] = p[1][3] + m[8] = p[2][0] + m[9] = p[2][1] + m[10] = p[2][2] + m[11] = p[2][3] + m[12] = p[3][0] + m[13] = p[3][1] + m[14] = p[3][2] + m[15] = p[3][3] return m - - + } @@ -119,23 +91,19 @@ export function m4lookAt(cameraPosition: Vec3, target: Vec3, up: Vec3): Mat4 { const yAxis = cross(zAxis, xAxis); normalize(yAxis) - return [ - xAxis.x, xAxis.y, xAxis.z, 0, - yAxis.x, yAxis.y, yAxis.z, 0, - zAxis.x, zAxis.y, zAxis.z, 0, - cameraPosition.x, - cameraPosition.y, - cameraPosition.z, - 1, + [xAxis.x, xAxis.y, xAxis.z, 0], + [yAxis.x, yAxis.y, yAxis.z, 0], + [zAxis.x, zAxis.y, zAxis.z, 0], + [cameraPosition.x, cameraPosition.y, cameraPosition.z, 1] ]; } export type Mat4Projection = [ - number, 0, 0, 0, - 0, number, 0, 0, - 0, 0, number,-1|0, - number, number, number, 0|1, + [number, 0, 0, 0], + [0, number, 0, 0], + [0, 0, number,-1|0], + [number, number, number, 0|1], ] export function m4perspective(fieldOfViewInRadians: number, aspect: number, near: number, far: number): Mat4Projection { @@ -143,10 +111,10 @@ export function m4perspective(fieldOfViewInRadians: number, aspect: number, near const rangeInv = 1.0 / (near - far); return [ - f / aspect, 0, 0, 0, - 0, f, 0, 0, - 0, 0, (near + far) * rangeInv, -1, - 0, 0, near * far * rangeInv * 2, 0 + [f / aspect, 0, 0, 0], + [0, f, 0, 0], + [0, 0, (near + far) * rangeInv, -1], + [0, 0, near * far * rangeInv * 2, 0] ]; } @@ -158,55 +126,48 @@ export function m4orthographic(left: number, right: number, bottom: number, top: const nf = 1 / (near - far); return [ - -2 * lr, 0, 0, 0, - 0, -2 * bt, 0, 0, - 0, 0, 2 * nf, 0, - (left + right) * lr, (top + bottom) * bt, (far + near) * nf, 1 + [-2 * lr, 0, 0, 0], + [0, -2 * bt, 0, 0], + [0, 0, 2 * nf, 0], + [(left + right) * lr, (top + bottom) * bt, (far + near) * nf, 1] ]; } export function m4multiply(a: Mat4, b: Mat4): Mat4 { - - const ap = m4AsPositions(a); - const bp = m4AsPositions(b); - const p: Mat4D = [ + return [ - [bp[0][0] * ap[0][0] + bp[0][1] * ap[1][0] + bp[0][2] * ap[2][0] + bp[0][3] * ap[3][0], - bp[0][0] * ap[0][1] + bp[0][1] * ap[1][1] + bp[0][2] * ap[2][1] + bp[0][3] * ap[3][1], - bp[0][0] * ap[0][2] + bp[0][1] * ap[1][2] + bp[0][2] * ap[2][2] + bp[0][3] * ap[3][2], - bp[0][0] * ap[0][3] + bp[0][1] * ap[1][3] + bp[0][2] * ap[2][3] + bp[0][3] * ap[3][3], - ], - [bp[1][0] * ap[0][0] + bp[1][1] * ap[1][0] + bp[1][2] * ap[2][0] + bp[1][3] * ap[3][0], - bp[1][0] * ap[0][1] + bp[1][1] * ap[1][1] + bp[1][2] * ap[2][1] + bp[1][3] * ap[3][1], - bp[1][0] * ap[0][2] + bp[1][1] * ap[1][2] + bp[1][2] * ap[2][2] + bp[1][3] * ap[3][2], - bp[1][0] * ap[0][3] + bp[1][1] * ap[1][3] + bp[1][2] * ap[2][3] + bp[1][3] * ap[3][3], - ], - [bp[2][0] * ap[0][0] + bp[2][1] * ap[1][0] + bp[2][2] * ap[2][0] + bp[2][3] * ap[3][0], - bp[2][0] * ap[0][1] + bp[2][1] * ap[1][1] + bp[2][2] * ap[2][1] + bp[2][3] * ap[3][1], - bp[2][0] * ap[0][2] + bp[2][1] * ap[1][2] + bp[2][2] * ap[2][2] + bp[2][3] * ap[3][2], - bp[2][0] * ap[0][3] + bp[2][1] * ap[1][3] + bp[2][2] * ap[2][3] + bp[2][3] * ap[3][3], - ], - [bp[3][0] * ap[0][0] + bp[3][1] * ap[1][0] + bp[3][2] * ap[2][0] + bp[3][3] * ap[3][0], - bp[3][0] * ap[0][1] + bp[3][1] * ap[1][1] + bp[3][2] * ap[2][1] + bp[3][3] * ap[3][1], - bp[3][0] * ap[0][2] + bp[3][1] * ap[1][2] + bp[3][2] * ap[2][2] + bp[3][3] * ap[3][2], - bp[3][0] * ap[0][3] + bp[3][1] * ap[1][3] + bp[3][2] * ap[2][3] + bp[3][3] * ap[3][3], - ] + [ b[0][0] * a[0][0] + b[0][1] * a[1][0] + b[0][2] * a[2][0] + b[0][3] * a[3][0], + b[0][0] * a[0][1] + b[0][1] * a[1][1] + b[0][2] * a[2][1] + b[0][3] * a[3][1], + b[0][0] * a[0][2] + b[0][1] * a[1][2] + b[0][2] * a[2][2] + b[0][3] * a[3][2], + b[0][0] * a[0][3] + b[0][1] * a[1][3] + b[0][2] * a[2][3] + b[0][3] * a[3][3] + ], + [ b[1][0] * a[0][0] + b[1][1] * a[1][0] + b[1][2] * a[2][0] + b[1][3] * a[3][0], + b[1][0] * a[0][1] + b[1][1] * a[1][1] + b[1][2] * a[2][1] + b[1][3] * a[3][1], + b[1][0] * a[0][2] + b[1][1] * a[1][2] + b[1][2] * a[2][2] + b[1][3] * a[3][2], + b[1][0] * a[0][3] + b[1][1] * a[1][3] + b[1][2] * a[2][3] + b[1][3] * a[3][3] + ], + [ b[2][0] * a[0][0] + b[2][1] * a[1][0] + b[2][2] * a[2][0] + b[2][3] * a[3][0], + b[2][0] * a[0][1] + b[2][1] * a[1][1] + b[2][2] * a[2][1] + b[2][3] * a[3][1], + b[2][0] * a[0][2] + b[2][1] * a[1][2] + b[2][2] * a[2][2] + b[2][3] * a[3][2], + b[2][0] * a[0][3] + b[2][1] * a[1][3] + b[2][2] * a[2][3] + b[2][3] * a[3][3] + ], + [ b[3][0] * a[0][0] + b[3][1] * a[1][0] + b[3][2] * a[2][0] + b[3][3] * a[3][0], + b[3][0] * a[0][1] + b[3][1] * a[1][1] + b[3][2] * a[2][1] + b[3][3] * a[3][1], + b[3][0] * a[0][2] + b[3][1] * a[1][2] + b[3][2] * a[2][2] + b[3][3] * a[3][2], + b[3][0] * a[0][3] + b[3][1] * a[1][3] + b[3][2] * a[2][3] + b[3][3] * a[3][3] + ] ] - return m4FromPositions(p) } - - - export function m4translation(tx: number, ty: number, tz: number): Mat4Translation { return [ - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - tx, ty, tz, 1, + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [tx, ty, tz, 1], ]; } @@ -215,10 +176,10 @@ export function m4xRotation(angleInRadians: number): Mat4XRotation { const s = Math.sin(angleInRadians); return [ - 1, 0, 0, 0, - 0, c, s, 0, - 0, -s, c, 0, - 0, 0, 0, 1, + [1, 0, 0, 0], + [0, c, s, 0], + [0, -s, c, 0], + [0, 0, 0, 1], ]; } @@ -227,10 +188,10 @@ export function m4yRotation(angleInRadians: number): Mat4YRotation { const s = Math.sin(angleInRadians); return [ - c, 0, -s, 0, - 0, 1, 0, 0, - s, 0, c, 0, - 0, 0, 0, 1, + [c, 0, -s, 0], + [0, 1, 0, 0], + [s, 0, c, 0], + [0, 0, 0, 1], ]; } @@ -239,19 +200,19 @@ export function m4zRotation(angleInRadians: number): Mat4ZRotation { const s = Math.sin(angleInRadians); return [ - c, s, 0, 0, - -s, c, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1, + [ c, s, 0, 0], + [-s, c, 0, 0], + [ 0, 0, 1, 0], + [ 0, 0, 0, 1], ]; } export function m4scaling(sx: number, sy: number, sz: number): Mat4 { return [ - sx, 0, 0, 0, - 0, sy, 0, 0, - 0, 0, sz, 0, - 0, 0, 0, 1, + [sx, 0, 0, 0], + [0, sy, 0, 0], + [0, 0, sz, 0], + [0, 0, 0, 1], ]; } @@ -276,122 +237,125 @@ export function m4scaling(sx: number, sy: number, sz: number): Mat4 { } -/** - * Transposes a matrix. - * @param {Matrix4} m matrix to transpose. - * @param {Matrix4} [dst] optional matrix to store result - * @return {Matrix4} dst or a new matrix if none provided - */ + export function m4transpose(m: Mat4) { const dst: Mat4 = [ - 0,0,0,0, - 0,0,0,0, - 0,0,0,0, - 0,0,0,0, + [0,0,0,0], + [0,0,0,0], + [0,0,0,0], + [0,0,0,0], ]; - dst[ 0] = m[0]; - dst[ 1] = m[4]; - dst[ 2] = m[8]; - dst[ 3] = m[12]; - dst[ 4] = m[1]; - dst[ 5] = m[5]; - dst[ 6] = m[9]; - dst[ 7] = m[13]; - dst[ 8] = m[2]; - dst[ 9] = m[6]; - dst[10] = m[10]; - dst[11] = m[14]; - dst[12] = m[3]; - dst[13] = m[7]; - dst[14] = m[11]; - dst[15] = m[15]; + dst[0][0] = m[0][0]; + dst[0][1] = m[1][0]; + dst[0][2] = m[2][0]; + dst[0][3] = m[3][0]; + + dst[1][0] = m[0][1]; + dst[1][1] = m[1][1]; + dst[1][2] = m[2][1]; + dst[1][3] = m[3][1]; + + dst[2][0] = m[0][2]; + dst[2][1] = m[1][2]; + dst[2][2] = m[2][2]; + dst[2][3] = m[3][2]; + + dst[3][0] = m[0][3]; + dst[3][1] = m[1][3]; + dst[3][2] = m[2][3]; + dst[3][3] = m[3][3]; return dst; } export function m4inverse(m: Mat4): Mat4 { - const p = m4AsPositions(m) - - const tmp_0 = p[2][2] * p[3][3]; - const tmp_1 = p[3][2] * p[2][3]; - const tmp_2 = p[1][2] * p[3][3]; - const tmp_3 = p[3][2] * p[1][3]; - const tmp_4 = p[1][2] * p[2][3]; - const tmp_5 = p[2][2] * p[1][3]; - const tmp_6 = p[0][2] * p[3][3]; - const tmp_7 = p[3][2] * p[0][3]; - const tmp_8 = p[0][2] * p[2][3]; - const tmp_9 = p[2][2] * p[0][3]; - const tmp_10 = p[0][2] * p[1][3]; - const tmp_11 = p[1][2] * p[0][3]; - const tmp_12 = p[2][0] * p[3][1]; - const tmp_13 = p[3][0] * p[2][1]; - const tmp_14 = p[1][0] * p[3][1]; - const tmp_15 = p[3][0] * p[1][1]; - const tmp_16 = p[1][0] * p[2][1]; - const tmp_17 = p[2][0] * p[1][1]; - const tmp_18 = p[0][0] * p[3][1]; - const tmp_19 = p[3][0] * p[0][1]; - const tmp_20 = p[0][0] * p[2][1]; - const tmp_21 = p[2][0] * p[0][1]; - const tmp_22 = p[0][0] * p[1][1]; - const tmp_23 = p[1][0] * p[0][1]; - - const t0 = (tmp_0 * p[1][1] + tmp_3 * p[2][1] + tmp_4 * p[3][1]) - - (tmp_1 * p[1][1] + tmp_2 * p[2][1] + tmp_5 * p[3][1]); - const t1 = (tmp_1 * p[0][1] + tmp_6 * p[2][1] + tmp_9 * p[3][1]) - - (tmp_0 * p[0][1] + tmp_7 * p[2][1] + tmp_8 * p[3][1]); - const t2 = (tmp_2 * p[0][1] + tmp_7 * p[1][1] + tmp_10 * p[3][1]) - - (tmp_3 * p[0][1] + tmp_6 * p[1][1] + tmp_11 * p[3][1]); - const t3 = (tmp_5 * p[0][1] + tmp_8 * p[1][1] + tmp_11 * p[2][1]) - - (tmp_4 * p[0][1] + tmp_9 * p[1][1] + tmp_10 * p[2][1]); - - const d = 1.0 / (p[0][0] * t0 + p[1][0] * t1 + p[2][0] * t2 + p[3][0] * t3); + + const tmp_0 = m[2][2] * m[3][3]; + const tmp_1 = m[3][2] * m[2][3]; + const tmp_2 = m[1][2] * m[3][3]; + const tmp_3 = m[3][2] * m[1][3]; + const tmp_4 = m[1][2] * m[2][3]; + const tmp_5 = m[2][2] * m[1][3]; + const tmp_6 = m[0][2] * m[3][3]; + const tmp_7 = m[3][2] * m[0][3]; + const tmp_8 = m[0][2] * m[2][3]; + const tmp_9 = m[2][2] * m[0][3]; + const tmp_10 = m[0][2] * m[1][3]; + const tmp_11 = m[1][2] * m[0][3]; + const tmp_12 = m[2][0] * m[3][1]; + const tmp_13 = m[3][0] * m[2][1]; + const tmp_14 = m[1][0] * m[3][1]; + const tmp_15 = m[3][0] * m[1][1]; + const tmp_16 = m[1][0] * m[2][1]; + const tmp_17 = m[2][0] * m[1][1]; + const tmp_18 = m[0][0] * m[3][1]; + const tmp_19 = m[3][0] * m[0][1]; + const tmp_20 = m[0][0] * m[2][1]; + const tmp_21 = m[2][0] * m[0][1]; + const tmp_22 = m[0][0] * m[1][1]; + const tmp_23 = m[1][0] * m[0][1]; + + const t0 = (tmp_0 * m[1][1] + tmp_3 * m[2][1] + tmp_4 * m[3][1]) - + (tmp_1 * m[1][1] + tmp_2 * m[2][1] + tmp_5 * m[3][1]); + const t1 = (tmp_1 * m[0][1] + tmp_6 * m[2][1] + tmp_9 * m[3][1]) - + (tmp_0 * m[0][1] + tmp_7 * m[2][1] + tmp_8 * m[3][1]); + const t2 = (tmp_2 * m[0][1] + tmp_7 * m[1][1] + tmp_10 * m[3][1]) - + (tmp_3 * m[0][1] + tmp_6 * m[1][1] + tmp_11 * m[3][1]); + const t3 = (tmp_5 * m[0][1] + tmp_8 * m[1][1] + tmp_11 * m[2][1]) - + (tmp_4 * m[0][1] + tmp_9 * m[1][1] + tmp_10 * m[2][1]); + + const d = 1.0 / (m[0][0] * t0 + m[1][0] * t1 + m[2][0] * t2 + m[3][0] * t3); return [ - d * t0, - d * t1, - d * t2, - d * t3, - d * ((tmp_1 * p[1][0] + tmp_2 * p[2][0] + tmp_5 * p[3][0]) - - (tmp_0 * p[1][0] + tmp_3 * p[2][0] + tmp_4 * p[3][0])), - d * ((tmp_0 * p[0][0] + tmp_7 * p[2][0] + tmp_8 * p[3][0]) - - (tmp_1 * p[0][0] + tmp_6 * p[2][0] + tmp_9 * p[3][0])), - d * ((tmp_3 * p[0][0] + tmp_6 * p[1][0] + tmp_11 * p[3][0]) - - (tmp_2 * p[0][0] + tmp_7 * p[1][0] + tmp_10 * p[3][0])), - d * ((tmp_4 * p[0][0] + tmp_9 * p[1][0] + tmp_10 * p[2][0]) - - (tmp_5 * p[0][0] + tmp_8 * p[1][0] + tmp_11 * p[2][0])), - d * ((tmp_12 * p[1][3] + tmp_15 * p[2][3] + tmp_16 * p[3][3]) - - (tmp_13 * p[1][3] + tmp_14 * p[2][3] + tmp_17 * p[3][3])), - d * ((tmp_13 * p[0][3] + tmp_18 * p[2][3] + tmp_21 * p[3][3]) - - (tmp_12 * p[0][3] + tmp_19 * p[2][3] + tmp_20 * p[3][3])), - d * ((tmp_14 * p[0][3] + tmp_19 * p[1][3] + tmp_22 * p[3][3]) - - (tmp_15 * p[0][3] + tmp_18 * p[1][3] + tmp_23 * p[3][3])), - d * ((tmp_17 * p[0][3] + tmp_20 * p[1][3] + tmp_23 * p[2][3]) - - (tmp_16 * p[0][3] + tmp_21 * p[1][3] + tmp_22 * p[2][3])), - d * ((tmp_14 * p[2][2] + tmp_17 * p[3][2] + tmp_13 * p[1][2]) - - (tmp_16 * p[3][2] + tmp_12 * p[1][2] + tmp_15 * p[2][2])), - d * ((tmp_20 * p[3][2] + tmp_12 * p[0][2] + tmp_19 * p[2][2]) - - (tmp_18 * p[2][2] + tmp_21 * p[3][2] + tmp_13 * p[0][2])), - d * ((tmp_18 * p[1][2] + tmp_23 * p[3][2] + tmp_15 * p[0][2]) - - (tmp_22 * p[3][2] + tmp_14 * p[0][2] + tmp_19 * p[1][2])), - d * ((tmp_22 * p[2][2] + tmp_16 * p[0][2] + tmp_21 * p[1][2]) - - (tmp_20 * p[1][2] + tmp_23 * p[2][2] + tmp_17 * p[0][2])) - ]; + [ + d * t0, + d * t1, + d * t2, + d * t3, + ], + [ + d * ((tmp_1 * m[1][0] + tmp_2 * m[2][0] + tmp_5 * m[3][0]) - + (tmp_0 * m[1][0] + tmp_3 * m[2][0] + tmp_4 * m[3][0])), + d * ((tmp_0 * m[0][0] + tmp_7 * m[2][0] + tmp_8 * m[3][0]) - + (tmp_1 * m[0][0] + tmp_6 * m[2][0] + tmp_9 * m[3][0])), + d * ((tmp_3 * m[0][0] + tmp_6 * m[1][0] + tmp_11 * m[3][0]) - + (tmp_2 * m[0][0] + tmp_7 * m[1][0] + tmp_10 * m[3][0])), + d * ((tmp_4 * m[0][0] + tmp_9 * m[1][0] + tmp_10 * m[2][0]) - + (tmp_5 * m[0][0] + tmp_8 * m[1][0] + tmp_11 * m[2][0])), + ], + [ + d * ((tmp_12 * m[1][3] + tmp_15 * m[2][3] + tmp_16 * m[3][3]) - + (tmp_13 * m[1][3] + tmp_14 * m[2][3] + tmp_17 * m[3][3])), + d * ((tmp_13 * m[0][3] + tmp_18 * m[2][3] + tmp_21 * m[3][3]) - + (tmp_12 * m[0][3] + tmp_19 * m[2][3] + tmp_20 * m[3][3])), + d * ((tmp_14 * m[0][3] + tmp_19 * m[1][3] + tmp_22 * m[3][3]) - + (tmp_15 * m[0][3] + tmp_18 * m[1][3] + tmp_23 * m[3][3])), + d * ((tmp_17 * m[0][3] + tmp_20 * m[1][3] + tmp_23 * m[2][3]) - + (tmp_16 * m[0][3] + tmp_21 * m[1][3] + tmp_22 * m[2][3])), + ], + [ + d * ((tmp_14 * m[2][2] + tmp_17 * m[3][2] + tmp_13 * m[1][2]) - + (tmp_16 * m[3][2] + tmp_12 * m[1][2] + tmp_15 * m[2][2])), + d * ((tmp_20 * m[3][2] + tmp_12 * m[0][2] + tmp_19 * m[2][2]) - + (tmp_18 * m[2][2] + tmp_21 * m[3][2] + tmp_13 * m[0][2])), + d * ((tmp_18 * m[1][2] + tmp_23 * m[3][2] + tmp_15 * m[0][2]) - + (tmp_22 * m[3][2] + tmp_14 * m[0][2] + tmp_19 * m[1][2])), + d * ((tmp_22 * m[2][2] + tmp_16 * m[0][2] + tmp_21 * m[1][2]) - + (tmp_20 * m[1][2] + tmp_23 * m[2][2] + tmp_17 * m[0][2])) + ] + ] + } export function m4Vec4multiply(m: Mat4, v: Vec4): Vec4 { - const mm = m4AsPositions(m) - return { - x: v.x * mm[0][0] + v.y * mm[1][0]! + v.z * mm[2][0]! + v.w * mm[3][0]!, - y: v.x * mm[0][1] + v.y * mm[1][1]! + v.z * mm[2][1]! + v.w * mm[3][1]!, - z: v.x * mm[0][2] + v.y * mm[1][2]! + v.z * mm[2][2]! + v.w * mm[3][2]!, - w: v.x * mm[0][3] + v.y * mm[1][3]! + v.z * mm[2][3]! + v.w * mm[3][3]! - + x: v.x * m[0][0] + v.y * m[1][0] + v.z * m[2][0] + v.w * m[3][0], + y: v.x * m[0][1] + v.y * m[1][1] + v.z * m[2][1] + v.w * m[3][1], + z: v.x * m[0][2] + v.y * m[1][2] + v.z * m[2][2] + v.w * m[3][2], + w: v.x * m[0][3] + v.y * m[1][3] + v.z * m[2][3] + v.w * m[3][3] } }