Skip to content
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(app): 105 Collision event #134

Merged
merged 4 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 45 additions & 28 deletions docs/components/collider.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,45 @@
# Collider

## Props

| Prop | Description | Default |
| :-------------- | :------------------------------------------------------------------------------------------------------------ | --------- |
| **shape** | shape of the collider | `cuboid` |
| **args** | The half-sizes of the collider shapes | `[1,1,1]` |
| **object** | Required for certain shapes like `trimesh`, `hull`, `heightfield`. | |
| **friction** | The friction coefficient of this collider. (automatic-collider) | `0.5` |
| **mass** | Mass of the collider. (automatic-collider) | `1` |
| **density** | Restitution controls how elastic (aka. bouncy) a contact is. (automatic-collider) | `0` |
| **restitution** | The collider density. If non-zero the collider's mass and angular inertia will be added. (automatic-collider) | `1` |

:::info
You can access the [Collider](https://rapier.rs/docs/user_guides/javascript/colliders) instance
which offers full control over all the properties & methods available
by using [Template refs](https://vuejs.org/guide/essentials/template-refs.html#template-refs).
:::

## Expose object

```
{
instance,
colliderDesc,
}
```
# Custom Colliders

## Collisions

Similar to [how collisions work in rigid-bodies](./rigid-body.md#collisions) you can set a custom collider to receive collisions events.

Be aware that the event will be emitted by the `RigidBody` parent

```html
...
<RigidBody @collision-enter="onCollisionEnter" @collision-exit="onCollisionExit">
<BallCollider activeCollision />
</RigidBody>
...
```

## Props

| Prop | Description | Default |
| :-------------- | :------------------------------------------------------------------------------------------------------------ | --------- |
| **shape** | shape of the collider | `cuboid` |
| **args** | The half-sizes of the collider shapes | `[1,1,1]` |
| **object** | Required for certain shapes like `trimesh`, `hull`, `heightfield`. | |
| **friction** | The friction coefficient of this collider. (automatic-collider) | `0.5` |
| **mass** | Mass of the collider. (automatic-collider) | `1` |
| **density** | Restitution controls how elastic (aka. bouncy) a contact is. (automatic-collider) | `0` |
| **restitution** | The collider density. If non-zero the collider's mass and angular inertia will be added. (automatic-collider) | `1` |
| **activeCollision** | To set the collider receiver/emitter collision events | `false` |
| **activeCollisionTypes** | Type of the collision event. | `ActiveCollisionTypes.DEFAULT` |
| **collisionGroups** | To specify collision groups. | `undefined` |

:::info
You can access the [Collider](https://rapier.rs/docs/user_guides/javascript/colliders) instance
which offers full control over all the properties & methods available
by using [Template refs](https://vuejs.org/guide/essentials/template-refs.html#template-refs).
:::

## Expose object

```
{
instance,
colliderDesc,
}
```
Expand Down
90 changes: 59 additions & 31 deletions docs/components/rigid-body.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
# RigidBody

:::info
The information in this page is a summary of the RigidBody instance,
:::info The information in this page is a summary of the RigidBody instance,
please check the
[complete documentation](https://rapier.rs/docs/user_guides/javascript/rigid_bodies)
for more info
:::
for more info :::

The real-time simulation of rigid-bodies subjected to forces and contacts is the
main feature of a physics engine for video-games, robotics, or animation.
Expand Down Expand Up @@ -54,11 +52,9 @@ A basic floor example with type fixed:
| `KinematicPositionBased` | Indicates that the body position must not be altered by the physics engine. |
| `KinematicVelocityBased` | Indicates that the body velocity must not be altered by the physics engine. |

:::info
Both position-based and velocity-based kinematic bodies are mostly the
:::info Both position-based and velocity-based kinematic bodies are mostly the
same. Choosing between both is mostly a matter of preference between
position-based control and velocity-based control.
:::
position-based control and velocity-based control. :::

More info at
[Rigid-body type](https://rapier.rs/docs/user_guides/javascript/rigid_bodies#rigid-body-type)
Expand Down Expand Up @@ -129,36 +125,68 @@ More info

## Collisions

To start receiving collisions events, first you need to set the
`active-collision` prop to our `RigidBody` (this set all our automatic
colliders). Then you can start listening for events in `@collision-enter` and/or
`@collision-exit`.

```html
...
<RigidBody activeCollision @collision-enter="onCollisionEnter" @collision-exit="onCollisionExit">
<TresMesh>
<TresBoxGeometry />
<TresMeshNormalMaterial />
</TresMesh>
</RigidBody>
...
```

- You can set continuous collision detection for fast moving object, passing as a
prop `enableCcd`.
- You can specify the collision type using
`activeCollisionTypes` props.
- Also you can set specific collision groups by
using the `collisionGroups` prop.

## Sensor

SOON

## Contact force

SOON

## Events
## Sleep/awake

SOON

## Props

| Prop | Description | Default |
| :---------------------- | :------------------------------------------------------------------------------------------------------------ | ------------------------------ |
| **type** | `rigidBody` type | `dynamic` |
| **collider** | automatic collider | `cuboid` |
| **gravityScale** | gravity for the `rigidBody` | `1` |
| **additionalMass** | add extra mass to the `rigidBody` | `0` |
| **linearDamping** | set the linear damping | `0` |
| **angularDamping** | set the angular damping | `0` |
| **dominanceGroup** | set the dominance group | `0` |
| **linvel** | linear velocity | `x: 0, y: 0, z: 0` |
| **angvel** | angular velocity | `x: 0, y: 0, z: 0` |
| **enabledRotations** | enable rotations in specific axis | `{x: true, y: true, z: true }` |
| **enabledTranslations** | enable translations in specific axis | `{x: true, y: true, z: true }` |
| **lockTranslations** | Lock all translations | `false` |
| **lockRotations** | Lock all rotations | `false` |
| **friction** | The friction coefficient of this collider. (automatic-collider) | `0.5` |
| **mass** | Mass of the collider. (automatic-collider) | `1` |
| **density** | Restitution controls how elastic (aka. bouncy) a contact is. (automatic-collider) | `0` |
| **restitution** | The collider density. If non-zero the collider's mass and angular inertia will be added. (automatic-collider) | `1` |

:::info
The `rigidBody` instance has many other functions, please check the
| Prop | Description | Default |
| :----------------------- | :------------------------------------------------------------------------------------------------------------ | ------------------------------ |
| **type** | `rigidBody` type | `dynamic` |
| **collider** | automatic collider | `cuboid` |
| **gravityScale** | gravity for the `rigidBody` | `1` |
| **additionalMass** | add extra mass to the `rigidBody` | `0` |
| **linearDamping** | set the linear damping | `0` |
| **angularDamping** | set the angular damping | `0` |
| **dominanceGroup** | set the dominance group | `0` |
| **linvel** | linear velocity | `x: 0, y: 0, z: 0` |
| **angvel** | angular velocity | `x: 0, y: 0, z: 0` |
| **enabledRotations** | enable rotations in specific axis | `{x: true, y: true, z: true }` |
| **enabledTranslations** | enable translations in specific axis | `{x: true, y: true, z: true }` |
| **lockTranslations** | Lock all translations | `false` |
| **lockRotations** | Lock all rotations | `false` |
| **enableCcd** | Enable continuous collision detection | `false` |
| **friction** | The friction coefficient of this collider. (automatic-collider) | `0.5` |
| **mass** | Mass of the collider. (automatic-collider) | `1` |
| **density** | Restitution controls how elastic (aka. bouncy) a contact is. (automatic-collider) | `0` |
| **restitution** | The collider density. If non-zero the collider's mass and angular inertia will be added. (automatic-collider) | `1` |
| **activeCollision** | To set the collider receiver/emitter collision events (automatic-collider) | `false` |
| **activeCollisionTypes** | Type of the collision event. (automatic-collider) | `ActiveCollisionTypes.DEFAULT` |
| **collisionGroups** | To specify collision groups. (automatic-collider) | `undefined` |

:::info The `rigidBody` instance has many other functions, please check the
[official docs](https://rapier.rs/docs/api/javascript/JavaScript3D/) for a
complete list, if you need them, you can
use[Template ref](https://vuejs.org/guide/essentials/template-refs.html#template-refs).
Expand Down
81 changes: 81 additions & 0 deletions playground/src/pages/basics/CollisionDemo.vue
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'
import { BallCollider, Physics, RigidBody } from '@tresjs/rapier'
import { ACESFilmicToneMapping, SRGBColorSpace } from 'three'
import { shallowRef } from 'vue'

const gl = {
clearColor: '#82DBC5',
shadows: true,
alpha: false,
outputColorSpace: SRGBColorSpace,
toneMapping: ACESFilmicToneMapping,
}

const rigidTorusRef = shallowRef()

const jump = () => {
if (!rigidTorusRef.value) { return }
rigidTorusRef.value.instance.applyImpulse({ x: 0, y: 5, z: 0 }, true)
}

const onCollisionEnter = (event: any) => {
// eslint-disable-next-line no-console
console.log('jaime ~ ENTER', event)
}
const onCollisionEnterBall = (event: any) => {
// eslint-disable-next-line no-console
console.log('jaime ~ ENTER', event.source.rapierGroup.collider.collisionGroups())
}
const onCollisionExit = (event: any) => {
// eslint-disable-next-line no-console
console.log('jaime ~ EXIT', event)
}
</script>

<template>
<TresCanvas v-bind="gl" window-size>
<TresPerspectiveCamera :position="[0, 11, 30]" :look-at="[0, 0, 0]" />
<OrbitControls />

<Suspense>
<Physics debug>
<RigidBody
ref="rigidTorusRef"
name="rigidTorus"
enableCcd
activeCollision
@collision-enter="onCollisionEnter"
@collision-exit="onCollisionExit"
>
<TresMesh :position="[0, 8, 0]" @click="jump">
<TresTorusGeometry />
<TresMeshNormalMaterial />
</TresMesh>
<TresMesh :position="[-5, 7, 0]">
<TresSphereGeometry />
<TresMeshNormalMaterial />
</TresMesh>
</RigidBody>

<RigidBody
@collision-enter="onCollisionEnterBall"
>
<BallCollider
activeCollision
:args="[1, 1, 1]"
:position="[8, 15, 0]"
/>
</RigidBody>

<RigidBody type="fixed" name="fixedFloor">
<TresMesh :position="[0, 0, 0]">
<TresPlaneGeometry :args="[20, 20, 20]" :rotate-x="-Math.PI / 2" />
<TresMeshBasicMaterial color="#f4f4f4" />
</TresMesh>
</RigidBody>
</Physics>
</Suspense>
</TresCanvas>
</template>
5 changes: 5 additions & 0 deletions playground/src/router/routes/basics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,9 @@ export const basicsRoutes = [
name: 'Props',
component: () => import('../../pages/basics/RigidBodyProps.vue'),
},
{
path: '/basics/collision',
name: 'Collision',
component: () => import('../../pages/basics/CollisionDemo.vue'),
},
]
24 changes: 21 additions & 3 deletions src/components/Physics.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
<script setup lang="ts">
import { useLoop } from '@tresjs/core'
import { EventQueue } from '@dimforge/rapier3d-compat'
import { useLoop, useTresContext } from '@tresjs/core'
import { Vector3 } from 'three'
import { watch } from 'vue'
import type { VectorCoordinates } from '@tresjs/core'
import { useRapierContextProvider } from '../composables/useRapier'

import { GRAVITY } from '../constants/physics'

import { collisionEmisor, get3DGroupFromSource, getSourceFromColliderHandle } from '../utils'
import Debug from './Debug.vue'
import type { PhysicsProps } from '../types'

Expand Down Expand Up @@ -34,6 +36,9 @@ const setGravity = (gravity: PhysicsProps['gravity']) => {
}
}

const eventQueue = new EventQueue(true)
const { scene } = useTresContext()

watch(() => props.gravity, (gravity) => {
setGravity(gravity)
}, { immediate: true })
Expand All @@ -46,7 +51,20 @@ onBeforeRender(() => {
world.timestep = props.timestep
}

world.step()
world.step(eventQueue)
eventQueue.drainCollisionEvents((handle1, handle2, started) => {
const source1 = getSourceFromColliderHandle(world, handle1)
const source2 = getSourceFromColliderHandle(world, handle2)
const group1 = get3DGroupFromSource(source1, scene)
const group2 = get3DGroupFromSource(source2, scene)
if (group1 && group2) {
collisionEmisor(
{ object: group1, context: source1 },
{ object: group2, context: source2 },
started,
)
}
})
})
</script>

Expand Down
13 changes: 12 additions & 1 deletion src/components/RigidBody.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script setup lang="ts">
import { ActiveCollisionTypes } from '@dimforge/rapier3d-compat'
import { useLoop } from '@tresjs/core'
import { Object3D } from 'three'
import { nextTick, onUnmounted, onUpdated, provide, shallowRef, watch } from 'vue'
Expand All @@ -24,12 +25,15 @@ const props = withDefaults(defineProps<Partial<RigidBodyProps>>(), {
enabledTranslations: () => ({ x: true, y: true, z: true }),
lockTranslations: false,
lockRotations: false,
enableCcd: false,
// Automatic collider props
friction: 0.5,
mass: 1,
restitution: 0,
density: 1,

activeCollision: false,
activeCollisionTypes: ActiveCollisionTypes.DEFAULT,
collisionGroups: undefined, // this is not working
})
const { onBeforeRender } = useLoop()
const { world } = useRapierContext()
Expand Down Expand Up @@ -101,6 +105,10 @@ watch([() => props.lockRotations, instance], ([_lockRotations, _]) => {
if (!instance.value) { return }
instance.value.lockRotations(_lockRotations, true)
})
watch([() => props.enableCcd, instance], ([_enableCcd, _]) => {
if (!instance.value) { return }
instance.value.enableCcd(_enableCcd)
})

onBeforeRender(() => {
const context = bodyContext.value
Expand Down Expand Up @@ -142,6 +150,9 @@ onUnmounted(() => {
:mass="props.mass"
:restitution="props.restitution"
:density="props.density"
:activeCollision="props.activeCollision"
:activeCollisionTypes="activeCollisionTypes"
:collisionGroups="collisionGroups"
/>
<slot v-once></slot>
</TresGroup>
Expand Down
Loading
Loading