Comments (9)
with your permission of course
Sure, feel free to take anything that is useful π
Hm, supposedly we could initialize the rigidbody in useLayoutEffect to get around that...
I think I had to create both the rigidbody and collider in a useLayoutEffect to avoid "layout shift" (not sure what it's called in a 3d context), was some time ago so don't remember exactly why I had to do it that way
from react-three-rapier.
Thanks for this! Indeed I will have to move everything into effects. It's just not nice working with current
all the time, and I was hoping to avoid it wherever I could, but I was not aware of these drawbacks.
Your adaption is really nice. Would you like to help flesh out r3f/rapier?
πΈπͺπ
from react-three-rapier.
@wiledal : To make the DX nicer, what about proxying the rigid body API calls?
Before:
- β Uses
useMemo
- β
Nice DX without
.current
// Package
export const useRigidBody = <O extends Object3D>(
// ...
const rigidBody = useMemo(() => {
// ...
const body = world.createRigidBody(rigidBodyDesc);
return body;
}, []);
// ...
return [ref as MutableRefObject<O>, rigidBody];
};
After:
- β
Uses
useEffect
- β
Nice DX without
.current
export const useRigidBody = <O extends Object3D>(
// ...
const rigidBodyRef = useRef();
useEffect(() => {
// ...
const body = world.createRigidBody(rigidBodyDesc);
rigidBodyRef.current.body;
}, []);
// ...
const api = createBodyApi(rigidBodyRef);
return [ref as MutableRefObject<O>, api];
};
function createBodyApi(bodyRef) {
return {
applyImpulse: (...args) => {
bodyRef.current.applyImpulse(...args);
},
applyTorqueImpulse: (...args) => {
bodyRef.current.applyImpulse(...args);
},
// ...
};
}
Would allow the same public API.
// Usage
const [box, rigidBody] = useCuboid(
{
position: [-4 + Math.random() * 8, 10, 0],
},
{
args: [0.5, 0.5, 0.5],
}
);
useEffect(() => {
rigidBody.applyImpulse({ x: 0, y: 0, z: 0 }, true);
rigidBody.applyTorqueImpulse({ x: 0, y: 0, z: Math.random() * 0.1 }, true);
}, []);
from react-three-rapier.
Your adaption is really nice. Would you like to help flesh out r3f/rapier?
Would be fun, I'm a bit short on time right now but if I get some spare time later I'll for sure see where I can contribute!
@Glavin001 The issue I hit with that approach is that you can't pass down the rigidbody in context to the child <Collider>
component (where it's needed in order to add it to the rapier world). React fires effects bottom-up, meaning the child (<Collider>
) won't have access to the rigidbody from the parent. Not sure if this makes sense, kinda hard to explain π¬
from react-three-rapier.
Would be fun, I'm a bit short on time right now but if I get some spare time later I'll for sure see where I can contribute!
No worries! I might lift some approaches from your repo, as you have it so neatly laid out -- with your permission of course π
function createBodyApi(bodyRef) {
I was thinking of doing this, but the extra work put me off for now. But, I will probably do it anyways because interacting with the api is annoying right now as you have to convert between Rapier's Vector3, Three's Vector3 back and forth for all interactions.
you can't pass down the rigidbody in context to the child
Hm, supposedly we could initialize the rigidbody in useLayoutEffect
to get around that...
from react-three-rapier.
Sure, feel free to take anything that is useful π
β¨
I've been doing some experiments, and from what I can tell it works okay initializing in a useLayoutEffect and returning a proxy api.
I have one strange useLayoutEffect
cleanup function that fires prematurely for some reason, but probably unrelated.
I feel there's big win to only have to deal with Three vector types, so I'll probably continue on this path.
from react-three-rapier.
@alexandernanberg you are right, useLayoutEffect
did not work as we also needed the world
to be initiated the same.
After more fiddling I believe a combination of these approaches is hitting the goldilocks sweetspot β¨
- Use the
RefGetter
(MutableRefObject<() => T>
) approach for "lazy" (or rather "eager"!) initiation of objects (world
,rigidbody
,collider
,joint
), as mentioned in the original post. - In a memoized proxy, use the
RefGetter
for all api forwarding
const createSomeApi = (refGetter) => ({
someFunc() => refGetter.current()!.someFunc()
})
const useSomething = () => {
const ref = useRef()
const refGetter = useRef(() => {
if (!ref.current) {
ref.current = new Something()
}
return ref.current
})
const api = useMemo(() => createSomeApi(refGetter), [])
return api
}
The result is an immediately accessible api, with eagerly initiated objects.
const [ref, api] = useRigidBody(...)
useEffect(() => {
api.applyImpulse(new Vector3(0,0,1))
}, [])
useFrame(() => {
refs.current.forEach((ref) => {
const p = ref.current.translation();
// since p is proxied to be a Vector3, we can easily apply all Threejs math on it
p.normalize().multiplyScalar(-0.02);
ref.current.applyImpulse(p);
});
});
from react-three-rapier.
I went through and applied these approaches for everything.
Going to double check so that all types are in place and usable asap.
See: #14 :)
from react-three-rapier.
I'm still not convinced useMemo
is the right choice here, since React can throw away the value at any time. A lazy state setter might be better (useState(() => createSomeApi(refGetter))
), but technically it might still violate the React rules since you're setting/getting the ref value in render (React 18 compatibility is hard π
)
from react-three-rapier.
Related Issues (20)
- How to update center of origin position? HOT 1
- RigidBody Hull & Trimesh Colliders resulting in errors HOT 1
- RigidBody Colliders are not updated. HOT 2
- Colliders on PathExtrusionGeometry
- Ghost RigidBody after using setNextKinematicRotation HOT 2
- Does react-three-rapier support RN app? HOT 10
- <CuboidCollider /> component doesn't get rerender! HOT 2
- Can i get the complete control of "when Rapier does run"? HOT 1
- Collider Scale and Position to RigidBody having no effect HOT 4
- Website is broken. HOT 2
- Some Demos are laggy in Edge browser. Is it only me? HOT 3
- PrismaticJointParams donβt match up with usePrismaticJoint HOT 3
- How can I apply RigidBody to extrudeGeometry? HOT 1
- Restore world from snapshot HOT 3
- How i can load RigidBody in order HOT 2
- How to apply forces to dynamically created RigidBodies? HOT 1
- Ball Collider Fails to Interact with HeightfieldCollider in React Three Rapier
- CollisionPayload - event and other types not directly available. HOT 5
- is there an option to recompute the world base on fiber's scene change?
- Make Rapier instance available outside React/hooks HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. πππ
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google β€οΈ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from react-three-rapier.