Skip to content

Commit

Permalink
change: renamed position -> translate and made it a float3 (#230)
Browse files Browse the repository at this point in the history
  • Loading branch information
hannojg authored Jul 15, 2024
1 parent 049e6c4 commit 7352870
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 57 deletions.
3 changes: 2 additions & 1 deletion package/example/Shared/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"packageManager": "yarn@3.6.4",
"scripts": {
"start": "react-native start",
"build:materials": "./scripts/compile-materials.sh"
"build:materials": "./scripts/compile-materials.sh",
"typescript": "tsc --noEmit"
},
"dependencies": {
"@react-navigation/native": "^6.1.17",
Expand Down
29 changes: 16 additions & 13 deletions package/example/Shared/src/AnimatedRotateSharedValues.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,34 @@
import * as React from 'react'
import { StyleSheet } from 'react-native'
import { FilamentScene, FilamentView, Camera, Skybox, DefaultLight, RenderCallback, Model, ModelInstance } from 'react-native-filament'
import {
FilamentScene,
FilamentView,
Camera,
Skybox,
DefaultLight,
RenderCallback,
Model,
ModelInstance,
Float3,
} from 'react-native-filament'
import DroneGlb from '~/assets/buster_drone.glb'
import { useCallback } from 'react'
import { useSharedValue } from 'react-native-worklets-core'
import { Rotation } from '../../../src/react/TransformContext'

function Renderer() {
const rotation = useSharedValue<Rotation>({
angleInRadians: 0,
axis: [0, 1, 0],
})
const rotation = useSharedValue<Float3>([0, 0, 0])

const renderCallback: RenderCallback = useCallback(() => {
'worklet'

rotation.value.angleInRadians += 0.01
if (rotation.value.angleInRadians >= Math.PI * 2) {
rotation.value[1] += 0.01
if (rotation.value[1] >= Math.PI * 2) {
// reset / don't overflow
rotation.value.angleInRadians = 0
rotation.value[1] = 0
}

// need to make a new object ref so that the listener fires
rotation.value = {
angleInRadians: rotation.value.angleInRadians,
axis: rotation.value.axis,
}
rotation.value = [rotation.value[0], rotation.value[1], rotation.value[2]]
}, [rotation])

return (
Expand Down
2 changes: 1 addition & 1 deletion package/example/Shared/src/CastShadow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ function Renderer() {
{/* Elevate the camera bit so we can see the shadow (the plane is on 0,0,0, so we wouldn't see any shadow if we didn't elevate) */}
<Camera cameraPosition={[0, 3, 8]} />

<Model source={Coin} castShadow={showShadow} receiveShadow={showShadow} position={[0, 2, 0]} />
<Model source={Coin} castShadow={showShadow} receiveShadow={showShadow} translate={[0, 2, 0]} />
</FilamentView>
<Button title={`Toggle Shadow (${showShadow ? 'enabled' : 'disabled'})`} onPress={() => setShowShadow((prev) => !prev)} />
</View>
Expand Down
2 changes: 1 addition & 1 deletion package/example/Shared/src/ChangeMaterials.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ function Renderer() {
<Camera />
<DefaultLight />

<ModelRenderer model={rocket} position={[0, -1, 0]} />
<ModelRenderer model={rocket} translate={[0, -1, 0]} />
</FilamentView>
<Button
title="Change Color"
Expand Down
14 changes: 2 additions & 12 deletions package/example/Shared/src/FadeOut.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
import * as React from 'react'
import { useEffect, useRef } from 'react'

import { Animated, Button, StyleSheet, View } from 'react-native'
import { Animated, Button, StyleSheet } from 'react-native'
import {
Camera,
DefaultLight,
FilamentScene,
FilamentView,
Float3,
getAssetFromModel,
Model,
ModelRenderer,
useBuffer,
useFilamentContext,
useModel,
} from 'react-native-filament'
Expand Down Expand Up @@ -45,13 +41,7 @@ function Renderer() {
<Camera />
<DefaultLight />

<ModelRenderer
model={model}
rotate={{
angleInRadians: Math.PI / 2,
axis: [1, 0, 0],
}}
/>
<ModelRenderer model={model} rotate={[75 * (Math.PI / 180), 0, 0]} />
</FilamentView>
<Button title="Fade out" onPress={fadeOut} />
</SafeAreaView>
Expand Down
2 changes: 1 addition & 1 deletion package/example/Shared/src/MultipleInstances.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ function Renderer() {
const z = 0 // Keep z the same if you're not using it for depth positioning

return (
<ModelInstance key={index} index={index} position={[x, y, z]}>
<ModelInstance key={index} index={index} translate={[x, y, z]}>
<Animator />
</ModelInstance>
)
Expand Down
31 changes: 14 additions & 17 deletions package/src/hooks/internal/useApplyTransformations.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useEffect, useRef } from 'react'
import { Rotation, TransformationProps } from '../../react/TransformContext'
import { TransformationProps } from '../../react/TransformContext'
import { useFilamentContext } from '../useFilamentContext'
import { AABB, Entity, Float3 } from '../../types'
import { areFloat3Equal, isWorkletSharedValue } from '../../utilities/helper'
Expand All @@ -18,17 +18,14 @@ type Params = {
* transformation context to it
*/
export function useApplyTransformations({ to: entity, transformProps, aabb }: Params) {
// const transformPropsFromContext = useContext(TransformContext)

// const mergedTransformationProps = useMergeTransformationProps(transformProps, transformPropsFromContext)
const { position, scale, rotate, transformToUnitCube, multiplyWithCurrentTransform = true } = transformProps ?? {}
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<Float3 | null>(null)
const prevRotate = useRef<Rotation>()
const prevRotate = useRef<Float3 | null>(null)
const prevPosition = useRef<Float3 | null>(null)

useEffect(() => {
Expand All @@ -43,17 +40,16 @@ export function useApplyTransformations({ to: entity, transformProps, aabb }: Pa
prevScale.current = scale
}

if (
rotate != null &&
!isWorkletSharedValue(rotate) &&
(rotate.angleInRadians !== prevRotate.current?.angleInRadians || !areFloat3Equal(rotate.axis, prevRotate.current?.axis))
) {
transformManager.setEntityRotation(entity, rotate.angleInRadians, rotate.axis, multiplyWithCurrentTransform)
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))) {
console.log('setEntityPosition', entity, position, multiplyWithCurrentTransform)
transformManager.setEntityPosition(entity, position, multiplyWithCurrentTransform)
prevPosition.current = position
}
Expand Down Expand Up @@ -96,8 +92,11 @@ export function useApplyTransformations({ to: entity, transformProps, aabb }: Pa

const unsubscribeRotate = rotate.addListener(() => {
'worklet'
const axis: Float3 = [rotate.value.axis['0'], rotate.value.axis['1'], rotate.value.axis['2']]
transformManager.setEntityRotation(entity, rotate.value.angleInRadians, axis, multiplyWithCurrentTransform)
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 () => {
Expand All @@ -119,6 +118,4 @@ export function useApplyTransformations({ to: entity, transformProps, aabb }: Pa
unsubscribePosition()
}
}, [entity, multiplyWithCurrentTransform, position, transformManager])

// return mergedTransformationProps
}
4 changes: 2 additions & 2 deletions package/src/react/Group.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ import { TransformationProps, TransformContext } from './TransformContext'

type GroupProps = PropsWithChildren<TransformationProps>

export function Group({ children, position, multiplyWithCurrentTransform = false }: GroupProps): React.ReactElement {
return <TransformContext.Provider value={{ position, multiplyWithCurrentTransform }}>{children}</TransformContext.Provider>
export function Group({ children, translate: position, multiplyWithCurrentTransform = false }: GroupProps): React.ReactElement {
return <TransformContext.Provider value={{ translate: position, multiplyWithCurrentTransform }}>{children}</TransformContext.Provider>
}
33 changes: 24 additions & 9 deletions package/src/react/TransformContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,32 @@ import React from 'react'
import { Float3 } from '../types'
import { ISharedValue } from 'react-native-worklets-core'

export type Rotation = {
angleInRadians: number
axis: Float3
}

// TODO: WithAnimatedProps ?

/**
* Transformations are applied in the order of scale -> rotate -> translate.
*/
export type TransformationProps = {
position?: Float3 | ISharedValue<Float3>
/**
* Position in meters. Unit is in meters.
* @default [0, 0, 0]
*/
translate?: Float3 | ISharedValue<Float3>

/**
* Scale for each axis. Unit is in meters.
*/
scale?: Float3 | ISharedValue<Float3>
rotate?: Rotation | ISharedValue<Rotation>

/**
* Rotation for each axis in radians.
*/
rotate?: Float3 | ISharedValue<Float3>

/**
* If true, the current transformation of the entity will be multiplied with the new transformation.
* @default true
*/
multiplyWithCurrentTransform?: boolean

/**
Expand All @@ -24,10 +39,10 @@ export type TransformationProps = {
export function extractTransformationProps<T extends TransformationProps>(
props: T
): [TransformationProps, Omit<T, keyof TransformationProps>] {
const { position, scale, rotate, multiplyWithCurrentTransform, transformToUnitCube, ...rest } = props
const { translate, scale, rotate, multiplyWithCurrentTransform, transformToUnitCube, ...rest } = props
return [
{
position,
translate,
scale,
rotate,
multiplyWithCurrentTransform,
Expand Down

0 comments on commit 7352870

Please sign in to comment.