diff --git a/src/app/Utils.ts b/src/app/Utils.ts index 055a3aad..b83dcf71 100644 --- a/src/app/Utils.ts +++ b/src/app/Utils.ts @@ -426,7 +426,6 @@ function stepJacobi(m: mat3): quat { mat3.mul(n, n, m) mat3.copy(m, n) } - // console.log('J1', q, m) if (m[2] * m[2] + m[6] * m[6] > 1e-6) { const pair = approxGivensQuat(m[0], 0.5 * (m[2] + m[6]), m[8]) const a = -pair[0] @@ -446,7 +445,6 @@ function stepJacobi(m: mat3): quat { mat3.mul(n, n, m) mat3.copy(m, n) } - // console.log('J2', q, m) if (m[5] * m[5] + m[7] * m[7] > 1e-6) { const [a, b] = approxGivensQuat(m[4], 0.5 * (m[5] + m[7]), m[8]) const r = quat.fromValues(a, 0, 0, b) @@ -464,7 +462,6 @@ function stepJacobi(m: mat3): quat { mat3.mul(n, n, m) mat3.copy(m, n) } - // console.log('J3', q, m) return q } @@ -474,17 +471,14 @@ export function svdDecompose(m: mat3): [quat, vec3, quat] { const n = mat3.create() mat3.transpose(n, m) mat3.mul(n, n, m) - // console.log('A', n) for (let i = 0; i < 5; i += 1) { quat.mul(r, r, stepJacobi(n)) } quat.normalize(r, r) - // console.log('B', r) const p0 = mat3.create() mat3.fromQuat(p0, r) mat3.mul(p0, m, p0) - // console.log('C', p0) let f = 1 const [a1, b1] = qrGivensQuat(p0[0], p0[1]) @@ -492,7 +486,6 @@ export function svdDecompose(m: mat3): [quat, vec3, quat] { const d1 = -2 * a1 * b1 const e1 = b1 * b1 + a1 * a1 const s1 = quat.fromValues(0, 0, a1, b1) - // console.log('D', s1) quat.mul(q, q, s1) const p1 = mat3.create() p1[0] = c1 @@ -502,7 +495,6 @@ export function svdDecompose(m: mat3): [quat, vec3, quat] { p1[8] = e1 f *= e1 mat3.mul(p1, p1, p0) - // console.log('E', p1) const pair = qrGivensQuat(p1[0], p1[2]) const a2 = -pair[0] @@ -519,7 +511,6 @@ export function svdDecompose(m: mat3): [quat, vec3, quat] { p2[6] = d2 p2[4] = e2 f *= e2 - // console.log('H2', f, e2) mat3.mul(p2, p2, p1) const [a3, b3] = qrGivensQuat(p2[4], p2[5]) @@ -536,7 +527,6 @@ export function svdDecompose(m: mat3): [quat, vec3, quat] { p3[0] = e3 f *= e3 mat3.mul(p3, p3, p2) - // console.log('G', p1) f = 1 / f quat.scale(q, q, Math.sqrt(f)) @@ -551,3 +541,12 @@ export function toAffine(m: mat4): mat4 { mat4.scale(n, n, [a, a, a]) return n } + +export function composeMatrix(translation: vec3, leftRotation: quat, scale: vec3, rightRotation: quat) { + const m = mat4.create() + mat4.translate(m, m, translation) + mat4.mul(m, m, mat4.fromQuat(mat4.create(), leftRotation)) + mat4.scale(m, m, scale) + mat4.mul(m, m, mat4.fromQuat(mat4.create(), rightRotation)) + return m +} diff --git a/src/app/pages/Transformation.tsx b/src/app/pages/Transformation.tsx index 56f93c65..645a8f79 100644 --- a/src/app/pages/Transformation.tsx +++ b/src/app/pages/Transformation.tsx @@ -5,7 +5,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'preact/hooks' import { Footer, NumberInput, Octicon, RangeInput } from '../components/index.js' import { InteractiveCanvas3D } from '../components/previews/InteractiveCanvas3D.jsx' import { useLocale, useTitle } from '../contexts/index.js' -import { svdDecompose, toAffine } from '../Utils.js' +import { composeMatrix, svdDecompose, toAffine } from '../Utils.js' interface Props { path?: string, @@ -14,6 +14,7 @@ export function Transformation({}: Props) { const { locale } = useLocale() useTitle(locale('title.transformation')) + const [matrix, setMatrix] = useState(mat4.create()) const [translation, setTranslation] = useState(vec3.create()) const [leftRotation, setLeftRotation] = useState(quat.create()) const [scale, setScale] = useState(vec3.fromValues(1, 1, 1)) @@ -29,16 +30,19 @@ export function Transformation({}: Props) { if (normalizeRight) setRightRotation(q => quat.normalize(quat.clone(q), q)) }, [normalizeRight]) - const matrix = useMemo(() => { - const m = mat4.create() - mat4.translate(m, m, translation) - mat4.mul(m, m, mat4.fromQuat(mat4.create(), leftRotation)) - mat4.scale(m, m, scale) - mat4.mul(m, m, mat4.fromQuat(mat4.create(), rightRotation)) - return m - }, [translation, leftRotation, scale, rightRotation]) + const [useMatrixOverride, setUseMatrixOverride] = useState(false) - const setMatrix = useCallback((m: mat4) => { + const usedMatrix = useMemo(() => { + if (matrix !== undefined && useMatrixOverride) { + return matrix + } + return composeMatrix(translation, leftRotation, scale, rightRotation) + }, [matrix, useMatrixOverride]) + + const changeMatrix = useCallback((i: number, value: number) => { + const m = mat4.clone(matrix) + m[i] = value + setMatrix(m) const affine = toAffine(m) const newTranslation = mat4.getTranslation(vec3.create(), affine) const [newLeftRotation, newScale, newRightRotation] = svdDecompose(mat3.fromMat4(mat3.create(), affine)) @@ -46,43 +50,37 @@ export function Transformation({}: Props) { setLeftRotation(newLeftRotation) setScale(newScale) setRightRotation(newRightRotation) - }, []) - - const changeMatrix = useCallback((i: number, value: number) => { - const m = mat4.clone(matrix) - m[i] = value - setMatrix(m) }, [matrix]) const changeTranslation = useCallback((i: number, value: number) => { const copy = vec3.clone(translation) copy[i] = value setTranslation(copy) - }, [translation]) + setMatrix(composeMatrix(translation, leftRotation, scale, rightRotation)) + }, [translation, leftRotation, scale, rightRotation]) const changeLeftRotation = useCallback((i: number, value: number) => { const copy = quat.clone(leftRotation) copy[i] = value - if (normalizeLeft) { - quat.normalize(copy, copy) - } + if (normalizeLeft) quat.normalize(copy, copy) setLeftRotation(copy) - }, [leftRotation, normalizeLeft]) + setMatrix(composeMatrix(translation, leftRotation, scale, rightRotation)) + }, [translation, leftRotation, scale, rightRotation, normalizeLeft]) const changeScale = useCallback((i: number, value: number) => { const copy = vec3.clone(scale) copy[i] = value setScale(copy) - }, [scale]) + setMatrix(composeMatrix(translation, leftRotation, scale, rightRotation)) + }, [translation, leftRotation, scale, rightRotation]) const changeRightRotation = useCallback((i: number, value: number) => { const copy = quat.clone(rightRotation) copy[i] = value - if (normalizeRight) { - quat.normalize(copy, copy) - } + if (normalizeRight) quat.normalize(copy, copy) setRightRotation(copy) - }, [rightRotation, normalizeRight]) + setMatrix(composeMatrix(translation, leftRotation, scale, rightRotation)) + }, [translation, leftRotation, scale, rightRotation, normalizeRight]) const renderer = useRef() const onSetup = useCallback((canvas: HTMLCanvasElement) => { @@ -94,8 +92,8 @@ export function Transformation({}: Props) { renderer.current?.setViewport(0, 0, width, height) }, []) const onDraw = useCallback((view: mat4) => { - renderer.current?.draw(view, matrix) - }, [matrix]) + renderer.current?.draw(view, usedMatrix) + }, [usedMatrix]) return
@@ -148,10 +146,11 @@ export function Transformation({}: Props) {
{locale('transformation.matrix')} + {matrix !== undefined && }
{Array(16).fill(0).map((_, i) =>
- changeMatrix(i, v)} readonly disabled /> - changeMatrix(i, v)} readonly disabled /> + changeMatrix(i, v)} /> + changeMatrix(i, v)} />
)}