mirror of
https://github.com/misode/misode.github.io.git
synced 2026-04-24 23:56:51 +00:00
Make matrix editable + add note about bugged behavior
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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>(mat4.create())
|
||||
const [translation, setTranslation] = useState<vec3>(vec3.create())
|
||||
const [leftRotation, setLeftRotation] = useState<quat>(quat.create())
|
||||
const [scale, setScale] = useState<vec3>(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<MeshRenderer>()
|
||||
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 <main class="has-preview">
|
||||
<div class="transformation-editor">
|
||||
@@ -148,10 +146,11 @@ export function Transformation({}: Props) {
|
||||
<div class="transformation-title">
|
||||
<span>{locale('transformation.matrix')}</span>
|
||||
<button class="tooltipped tip-se" aria-label={locale('reset')} onClick={() => setMatrix(mat4.create())}>{Octicon['history']}</button>
|
||||
{matrix !== undefined && <button class="tooltipped tip-se" aria-label={`${useMatrixOverride ? 'Expected' : 'Current'} behavior (see MC-259853)`} onClick={() => setUseMatrixOverride(!useMatrixOverride)}>{Octicon['info']}</button>}
|
||||
</div>
|
||||
{Array(16).fill(0).map((_, i) => <div class="transformation-input">
|
||||
<NumberInput value={matrix[i].toFixed(3)} onChange={v => changeMatrix(i, v)} readonly disabled />
|
||||
<RangeInput min={-1} max={1} step={0.01} value={matrix[i]} onChange={v => changeMatrix(i, v)} readonly disabled />
|
||||
<NumberInput value={matrix[i].toFixed(3)} onChange={v => changeMatrix(i, v)} />
|
||||
<RangeInput min={-1} max={1} step={0.01} value={matrix[i]} onChange={v => changeMatrix(i, v)} />
|
||||
</div>)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user