react-native-filament-buildcores
Version:
A real-time physically based 3D rendering engine for React Native
97 lines (93 loc) • 3.96 kB
JavaScript
import { useEffect, useRef } from 'react';
import { useFilamentContext } from '../useFilamentContext';
import { areFloat3Equal, isWorkletSharedValue } from '../../utilities/helper';
import { useWorkletEffect } from '../useWorkletEffect';
/**
* Takes the next entity from the context and applies all transformations from the next
* transformation context to it
*/
export function useApplyTransformations({
to: entity,
transformProps,
aabb
}) {
const {
translate: position,
scale,
rotate,
transformToUnitCube,
multiplyWithCurrentTransform = true
} = transformProps ?? {};
const {
transformManager
} = useFilamentContext();
// TODO: multiplying current transformations is a bit problematic with react.
// E.g. in strict mode or concurrent rendering our effects can be called multiple times.
// Running an effect multiple times with transformation multiplication can lead to unexpected results.
const prevScale = useRef(null);
const prevRotate = useRef(null);
const prevPosition = useRef(null);
useEffect(() => {
if (entity == null) return;
if (transformToUnitCube && aabb != null) {
transformManager.transformToUnitCube(entity, aabb);
}
if (Array.isArray(scale) && (prevScale.current == null || !areFloat3Equal(scale, prevScale.current))) {
transformManager.setEntityScale(entity, scale, multiplyWithCurrentTransform);
prevScale.current = scale;
}
if (Array.isArray(rotate) && (prevRotate.current == null || !areFloat3Equal(rotate, prevRotate.current))) {
const [x, y, z] = rotate;
transformManager.setEntityRotation(entity, x, [1, 0, 0], multiplyWithCurrentTransform);
// Rotation across axis is one operation so we need to always multiply the remaining rotations:
transformManager.setEntityRotation(entity, y, [0, 1, 0], true);
transformManager.setEntityRotation(entity, z, [0, 0, 1], true);
prevRotate.current = rotate;
}
if (Array.isArray(position) && (prevPosition.current == null || !areFloat3Equal(position, prevPosition.current))) {
transformManager.setEntityPosition(entity, position, multiplyWithCurrentTransform);
prevPosition.current = position;
}
}, [aabb, entity, multiplyWithCurrentTransform, position, prevPosition, prevRotate, prevScale, rotate, scale, transformManager, transformToUnitCube]);
// Effects for when a transform option is a shared value (SRT)
useEffect(() => {
if (entity == null) return;
if (scale == null || Array.isArray(scale)) return;
const unsubscribeScale = scale.addListener(() => {
transformManager.setEntityScale(entity, scale.value, multiplyWithCurrentTransform);
});
return () => {
unsubscribeScale();
};
}, [entity, multiplyWithCurrentTransform, scale, transformManager]);
useWorkletEffect(() => {
'worklet';
if (entity == null) return;
if (rotate == null || !isWorkletSharedValue(rotate)) {
return;
}
const unsubscribeRotate = rotate.addListener(() => {
'worklet';
const [x, y, z] = rotate.value;
transformManager.setEntityRotation(entity, x, [1, 0, 0], multiplyWithCurrentTransform);
// Rotation across axis is one operation so we need to always multiply the remaining rotations:
transformManager.setEntityRotation(entity, y, [0, 1, 0], true);
transformManager.setEntityRotation(entity, z, [0, 0, 1], true);
});
return () => {
'worklet';
unsubscribeRotate();
};
});
useEffect(() => {
if (entity == null) return;
if (position == null || Array.isArray(position)) return;
const unsubscribePosition = position.addListener(() => {
transformManager.setEntityPosition(entity, position.value, multiplyWithCurrentTransform);
});
return () => {
unsubscribePosition();
};
}, [entity, multiplyWithCurrentTransform, position, transformManager]);
}
//# sourceMappingURL=useApplyTransformations.js.map