-
-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Joints
implementation
#150
base: main
Are you sure you want to change the base?
Changes from 9 commits
2137ae8
37096db
cebe338
d5e58d6
93965e1
c531dfa
8c4afea
5b89fee
c1a6ffd
778d943
49ff2a4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
# Joints | ||
|
||
Joints is an extension feature provided in [Rapier#Joint](https://rapier.rs/docs/user_guides/javascript/joints/). It lets us connect two or more bodies, restricting their movements according to each other. | ||
|
||
In **TresJs** we can achieve such motion restriction by using one of the available components designed to handle joints: | ||
|
||
- [GenericJoint](../../src/components/joints/index.ts#L41) | ||
- [PrismaticJoint](../../src/components/joints/index.ts#L51) | ||
- [RevoluteJoint](../../src/components/joints/index.ts#L60) | ||
- [RopeJoint](../../src/components/joints/index.ts#L69) | ||
- [SphericalJoint](../../src/components/joints/index.ts#L78) | ||
- [SpringJoint](../../src/components/joints/index.ts#L86) | ||
|
||
All of them extends [BaseJoint](../../src/components/joints/index.ts#L96). | ||
|
||
## How to use | ||
|
||
Here's a basic `Joints` implementation in **TresJs**: | ||
|
||
```vue | ||
<script setup> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi @Neosoulink examples should be in Typescript as much as possible: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Got it |
||
import { RigidBody, SphericalJoint } from '@tresjs/rapier' | ||
import { shallowRef } from 'vue' | ||
|
||
const bodyRefA = shallowRef(null) | ||
const bodyRefB = shallowRef(null) | ||
</script> | ||
|
||
<template> | ||
<RigidBody | ||
ref="bodyRefA" | ||
type="kinematic" | ||
:position="[0, 0, 0]" | ||
collider="ball" | ||
> | ||
<TresMesh> | ||
<TresSphereGeometry /> | ||
<TresMeshNormalMaterial /> | ||
</TresMesh> | ||
</RigidBody> | ||
|
||
<RigidBody | ||
ref="bodyRefB" | ||
:position="[-2.2, 0, 0]" | ||
collider="ball" | ||
> | ||
<TresMesh> | ||
<TresSphereGeometry /> | ||
<TresMeshNormalMaterial /> | ||
</TresMesh> | ||
</RigidBody> | ||
|
||
<SphericalJoint | ||
:bodies="[bodyRefA?.instance, bodyRefB?.instance]" | ||
:params="[ | ||
[0, -1.1, 0], | ||
[0, 2, 0], | ||
]" | ||
/> | ||
</template> | ||
``` | ||
|
||
> Preview | ||
<img width="1141" alt="JointsDemo" src="https://github.com/user-attachments/assets/d3cacac3-8764-4906-886a-d0b7a764b7c0" /> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Neosoulink Why not using the normal markdown image notation for this?
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It was automatically added from github, but let make it clean. I'm going to update it |
||
|
||
### Explanation | ||
|
||
In the above example, we created 2 `RigidBody` references, then, we implemented the `SphericalJoint` component, by placing our 2 `RigidBody` references in the `:bodies` property and specifying parameters, we created a `spherical-joint` between them. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we created two |
||
|
||
:::info | ||
To understand how each Joint type works, please take a look at the official [Rapier Joint Documentation](https://rapier.rs/docs/user_guides/javascript/joints). | ||
::: |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
<script setup lang="ts"> | ||
import { OrbitControls } from '@tresjs/cientos' | ||
import { TresCanvas } from '@tresjs/core' | ||
// eslint-disable-next-line ts/ban-ts-comment | ||
// @ts-ignore | ||
import { type ExposedRigidBody, Physics, RigidBody, SphericalJoint } from '@tresjs/rapier' | ||
import { ACESFilmicToneMapping, Quaternion, SRGBColorSpace } from 'three' | ||
import { onMounted, onUnmounted, shallowRef } from 'vue' | ||
import type { ShallowRef } from 'vue' | ||
|
||
const gl = { | ||
clearColor: '#82DBC5', | ||
shadows: true, | ||
alpha: false, | ||
outputColorSpace: SRGBColorSpace, | ||
toneMapping: ACESFilmicToneMapping, | ||
} | ||
|
||
const yRotation = shallowRef(0) | ||
const bodyRefs = shallowRef<ShallowRef[]>( | ||
Array.from({ length: 10 }).map(() => shallowRef<ExposedRigidBody>(null)), | ||
) | ||
const currentInterval = shallowRef<NodeJS.Timeout | undefined>(undefined) | ||
|
||
onMounted(() => { | ||
currentInterval.value = setInterval(() => { | ||
const body = bodyRefs.value[0].value?.[0]?.instance | ||
if (!body) { return } | ||
|
||
yRotation.value = yRotation.value + 1 | ||
|
||
body.setNextKinematicRotation(new Quaternion(0, Math.sin(yRotation.value) * 1.5, 0, 1)) | ||
}, 1000) | ||
}) | ||
|
||
onUnmounted(() => | ||
clearInterval(currentInterval.value), | ||
) | ||
</script> | ||
|
||
<template> | ||
<TresCanvas v-bind="gl" window-size> | ||
<TresPerspectiveCamera :position="[0, 0, 30]" :look-at="[0, 0, 0]" /> | ||
<OrbitControls /> | ||
|
||
<Suspense> | ||
<Physics debug> | ||
<RigidBody | ||
v-for="(ref, i) in bodyRefs" | ||
:key="i" | ||
:ref="ref" | ||
:type="i === 0 ? 'kinematic' : 'dynamic'" | ||
:position="[i * 1.5, 0, 0]" | ||
collider="ball" | ||
> | ||
<TresMesh> | ||
<TresSphereGeometry /> | ||
<TresMeshNormalMaterial /> | ||
</TresMesh> | ||
</RigidBody> | ||
|
||
<SphericalJoint | ||
v-for="(ref, i) in bodyRefs" | ||
:key="i" | ||
:bodies="[ref.value?.[0]?.instance, bodyRefs[i - 1]?.value?.[0]?.instance]" | ||
:params="[ | ||
[-1.1, 0, 0], | ||
[1.1, 0, 0], | ||
]" | ||
/> | ||
|
||
<RigidBody type="fixed"> | ||
<TresMesh :position="[0, -10, 0]"> | ||
<TresPlaneGeometry :args="[40, 40, 20]" :rotate-x="-Math.PI / 2" /> | ||
<TresMeshBasicMaterial color="#f4f4f4" /> | ||
</TresMesh> | ||
</RigidBody> | ||
</Physics> | ||
</Suspense> | ||
</TresCanvas> | ||
</template> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
<script setup lang="ts"> | ||
import { OrbitControls } from '@tresjs/cientos' | ||
import { TresCanvas } from '@tresjs/core' | ||
// eslint-disable-next-line ts/ban-ts-comment | ||
// @ts-ignore | ||
import { type ExposedRigidBody, Physics, RigidBody, SphericalJoint } from '@tresjs/rapier' | ||
import { ACESFilmicToneMapping, SRGBColorSpace } from 'three' | ||
import { shallowRef } from 'vue' | ||
import type { ShallowRef } from 'vue' | ||
|
||
const gl = { | ||
clearColor: '#82DBC5', | ||
shadows: true, | ||
alpha: false, | ||
outputColorSpace: SRGBColorSpace, | ||
toneMapping: ACESFilmicToneMapping, | ||
} | ||
|
||
const bodyRefA: ShallowRef<ExposedRigidBody> = shallowRef(null) | ||
const bodyRefB: ShallowRef<ExposedRigidBody> = shallowRef(null) | ||
</script> | ||
|
||
<template> | ||
<TresCanvas v-bind="gl" window-size> | ||
<TresPerspectiveCamera :position="[0, 0, 30]" :look-at="[0, 0, 0]" /> | ||
<OrbitControls /> | ||
|
||
<Suspense> | ||
<Physics debug> | ||
<RigidBody | ||
ref="bodyRefA" | ||
type="kinematic" | ||
:position="[0, 0, 0]" | ||
collider="ball" | ||
> | ||
<TresMesh> | ||
<TresSphereGeometry /> | ||
<TresMeshNormalMaterial /> | ||
</TresMesh> | ||
</RigidBody> | ||
|
||
<RigidBody | ||
ref="bodyRefB" | ||
:position="[-2.2, 0, 0]" | ||
collider="ball" | ||
> | ||
<TresMesh> | ||
<TresSphereGeometry /> | ||
<TresMeshNormalMaterial /> | ||
</TresMesh> | ||
</RigidBody> | ||
|
||
<SphericalJoint | ||
:bodies="[bodyRefA?.instance, bodyRefB?.instance]" | ||
:params="[ | ||
[0, -1.1, 0], | ||
[0, 2, 0], | ||
]" | ||
/> | ||
|
||
<RigidBody type="fixed"> | ||
<TresMesh :position="[0, -8, 0]"> | ||
<TresPlaneGeometry :args="[40, 40, 20]" :rotate-x="-Math.PI / 2" /> | ||
<TresMeshBasicMaterial color="#f4f4f4" /> | ||
</TresMesh> | ||
</RigidBody> | ||
</Physics> | ||
</Suspense> | ||
</TresCanvas> | ||
</template> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
export * from './colliders' | ||
export { default as InstancedRigidBody } from './InstancedRigidBody.vue' | ||
export * from './joints' | ||
export { default as Physics } from './Physics.vue' | ||
export { default as RigidBody } from './RigidBody.vue' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Neosoulink you need to add the entry on
docs/.vitepress/config
so it's available on the side navigationThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noted