Skip to content

Commit

Permalink
fix applying options to rotation
Browse files Browse the repository at this point in the history
  • Loading branch information
bbohlender committed Jan 11, 2025
1 parent 5b32f6c commit a7cfbf4
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 40 deletions.
26 changes: 14 additions & 12 deletions examples/handle/door.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,20 @@ export function Door(props: JSX.IntrinsicElements['group']) {
material={materials.Door}
position={[0.852, 0.017, 0.782]}
/>
<group position={[0.81, 0.043, 0.803]}>
<HandleTarget>
<Handle
stopPropagation={false}
translate={false}
scale={false}
rotate={{ x: false, y: true, z: false }}
>
<mesh geometry={nodes.Circle002_Glossy_0.geometry} material={materials.Glossy} />
</Handle>
</HandleTarget>
</group>
<Handle translate="as-rotate" rotate={{ x: false, y: false, z: [-Math.PI, 0] }}>
<group position={[0.81, 0.043, 0.803]}>
<HandleTarget>
<Handle
stopPropagation={false}
translate={false}
scale={false}
rotate={{ x: false, y: [-Math.PI / 2, 0], z: false }}
>
<mesh geometry={nodes.Circle002_Glossy_0.geometry} material={materials.Glossy} />
</Handle>
</HandleTarget>
</group>
</Handle>
</HandleTarget>
</group>
<mesh geometry={nodes.Plane002_Glossy_0.geometry} material={materials.Glossy} />
Expand Down
63 changes: 35 additions & 28 deletions packages/handle/src/computations/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Euler, Matrix4, Plane, Quaternion, Vector3, Vector3Tuple } from 'three'
import { Euler, EulerOrder, Matrix4, Plane, Quaternion, Vector3, Vector3Tuple } from 'three'
import { Axis, HandleTransformState } from '../state.js'
import { HandleOptions, HandleTransformOptions } from '../store.js'
import { clamp } from 'three/src/math/MathUtils.js'
Expand All @@ -13,6 +13,12 @@ export type BaseHandleStoreData = {
initialTargetScale: Vector3
}

const axisFirstOrder = {
x: 'XYZ',
y: 'YXZ',
z: 'ZXY',
}

export function computeHandleTransformState(
time: number,
pointerAmount: number,
Expand Down Expand Up @@ -47,6 +53,7 @@ export function computeHandleTransformState(
quaternion.copy(storeData.initialTargetQuaternion)
rotation = storeData.initialTargetRotation.clone()
} else if (
Array.isArray(rotateOptions) ||
rotateOptions === true ||
(typeof rotateOptions != 'string' &&
!Array.isArray(rotateOptions) &&
Expand All @@ -55,6 +62,18 @@ export function computeHandleTransformState(
rotateOptions.z === true)
) {
rotation = new Euler().setFromQuaternion(quaternion, storeData.initialTargetRotation.order)
} else if (typeof rotateOptions === 'string') {
const order = axisFirstOrder[rotateOptions]
rotation = new Euler().setFromQuaternion(quaternion)
for (const orderElement of order) {
const axis = orderElement.toLowerCase() as Axis
if (axis === rotateOptions) {
continue
}
rotation[axis] = 0
}
rotation.order = storeData.initialTargetRotation.order
quaternion.setFromEuler(rotation)
} else {
rotation = applyTransformOptionsToRotation(quaternion, storeData.initialTargetRotation, rotateOptions)
}
Expand Down Expand Up @@ -105,39 +124,28 @@ function getPerpendicular(target: Vector3, from: Vector3): void {
target.set(-from.y, from.x, 0)
}

const quaternionHelper = new Quaternion()
const eulerHelper = new Euler()

export function applyTransformOptionsToRotation(
currentRotation: Quaternion,
initialRotation: Euler,
options: HandleTransformOptions,
options: Exclude<HandleTransformOptions, boolean | Array<Vector3Tuple> | Axis>,
): Euler {
const result = new Euler(0, 0, 0, initialRotation.order)
let inverted = false
for (const axisElement of initialRotation.order) {
const axis = axisElement.toLowerCase() as Axis
const axisAngle =
eulerHelper.setFromQuaternion(currentRotation, initialRotation.order)[axis] + (inverted ? Math.PI : 0)
const transformedAxisAngle = Array.isArray(options)
? axisAngle
: applyTransformOptionsToAxis(axis, axisAngle, initialRotation[axis], options)

if (Math.abs(axisAngle - transformedAxisAngle) > Math.PI / 2) {
inverted = !inverted
}

if (axisAngle != transformedAxisAngle) {
//currentRotation = currentRotation * result-1 * delta * result
currentRotation.multiply(quaternionHelper.setFromEuler(result).invert())
const delta = axisAngle - transformedAxisAngle
result[axis] = delta
currentRotation.multiply(quaternionHelper.setFromEuler(result))
let orderEnabledAxis = ''
let orderDisabledAxis = ''
for (const orderElement of initialRotation.order) {
if (options[orderElement.toLowerCase() as Axis] === false) {
orderDisabledAxis += orderElement
} else {
orderEnabledAxis += orderElement
}

result[axis] = transformedAxisAngle
}
const order = (orderEnabledAxis + orderDisabledAxis) as EulerOrder
const result = new Euler().setFromQuaternion(currentRotation, order)
for (const orderElement of order) {
const axis = orderElement.toLowerCase() as Axis
result[axis] = applyTransformOptionsToAxis(axis, result[axis], initialRotation[axis], options)
}
currentRotation.setFromEuler(result)
result.setFromQuaternion(currentRotation, initialRotation.order)
return result
}

Expand Down Expand Up @@ -453,7 +461,6 @@ export function projectOntoAxis(
//angleDifference is between 3° and 6°
//factor = 1 means that we want 100% from worldPoint and 0 from project point
const factor = (angleDifference - _3Degree) / _3Degree
console.log(factor)
projectPointOntoAxis(vectorHelper, initialWorldPoint, axis)
worldPoint.multiplyScalar(factor).addScaledVector(vectorHelper, 1 - factor)
}
Expand Down

0 comments on commit a7cfbf4

Please sign in to comment.