Skip to content

Commit

Permalink
docs: add physics v2 example
Browse files Browse the repository at this point in the history
  • Loading branch information
pjoe authored and brianzinn committed Oct 26, 2023
1 parent 8719bfe commit b955f6d
Show file tree
Hide file tree
Showing 4 changed files with 242 additions and 0 deletions.
100 changes: 100 additions & 0 deletions packages/static/content/examples/physics/BouncySphere2.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { FresnelParameters } from '@babylonjs/core/Materials/fresnelParameters'
import { Texture } from '@babylonjs/core/Materials/Textures/texture'
import { Color3 } from '@babylonjs/core/Maths/math.color'
import { Vector3 } from '@babylonjs/core/Maths/math.vector'
import { Mesh } from '@babylonjs/core/Meshes/mesh'
import { PhysicsShapeType } from '@babylonjs/core/Physics/v2/IPhysicsEnginePlugin'
import { PhysicsAggregate } from '@babylonjs/core/Physics/v2/physicsAggregate'
import { Nullable } from '@babylonjs/core/types'
import { AdvancedDynamicTexture } from '@babylonjs/gui/2D/advancedDynamicTexture'
import { useRef, useEffect, FC } from 'react'

type BouncySphereProps = {
fontsReady: boolean
position: Vector3
name: string
color: Color3
}

const BouncySphere: FC<BouncySphereProps> = ({ fontsReady, position, name, color }) => {
const sphereAggRef = useRef<Nullable<PhysicsAggregate>>(null)
const adtRef = useRef<AdvancedDynamicTexture | null>(null)

useEffect(() => {
if (adtRef.current) {
console.log('marking dirty')
adtRef.current!.markAsDirty()
} else {
console.log('no ref')
}
}, [fontsReady, adtRef])

const onButtonClicked = () => {
if (sphereAggRef.current) {
sphereAggRef.current.body!.applyImpulse(
Vector3.Up().scale(10),
sphereAggRef.current.transformNode.getAbsolutePosition()
)
}
}

return (
<sphere name={`${name}-sphere`} diameter={2} segments={16} position={position}>
<physicsAggregate
ref={sphereAggRef}
type={PhysicsShapeType.SPHERE}
_options={{ mass: 1, restitution: 0.9 }}
/>
<standardMaterial
name={`${name}-material`}
specularPower={16}
diffuseColor={Color3.Black()}
emissiveColor={color}
reflectionFresnelParameters={FresnelParameters.Parse({
isEnabled: true,
leftColor: [1, 1, 1],
rightColor: [0, 0, 0],
bias: 0.1,
power: 1,
})}
/>
<plane
name={`${name}-dialog`}
size={2}
position={new Vector3(0, 1.5, 0)}
sideOrientation={Mesh.BACKSIDE}
>
<advancedDynamicTexture
name="dialogTexture"
ref={adtRef}
height={1024}
width={1024}
createForParentMesh={true}
hasAlpha={true}
generateMipMaps={true}
samplingMode={Texture.TRILINEAR_SAMPLINGMODE}
>
<rectangle name={`${name}-rect`} height={0.5} width={1} thickness={12} cornerRadius={12}>
<rectangle>
<babylon-button
name={`${name}-close-icon`}
background="green"
onPointerDownObservable={onButtonClicked}
>
<textBlock
text={`${fontsReady ? '\uf00d' : 'X'} click ${name}`}
fontFamily="FontAwesome"
fontStyle="bold"
fontSize={200}
color="white"
/>
</babylon-button>
</rectangle>
</rectangle>
</advancedDynamicTexture>
</plane>
</sphere>
)
}

export default BouncySphere
123 changes: 123 additions & 0 deletions packages/static/content/examples/physics/Physics2.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import React, { useState, useRef, FC, useEffect } from 'react'

import '@babylonjs/core/Physics/physicsEngineComponent' // side-effect adds scene.enablePhysics function
import '@babylonjs/core/Lights/Shadows/shadowGeneratorSceneComponent' // side-effect for shadow generator
import { HavokPlugin } from '@babylonjs/core/Physics/v2/Plugins/havokPlugin'
import { Vector3 } from '@babylonjs/core/Maths/math.vector'
import { PhysicsShapeType } from '@babylonjs/core/Physics/v2/IPhysicsEnginePlugin'

import { Scene, Engine } from 'react-babylonjs'

import BouncySphere from './BouncySphere2'

import HavokPhysics, { HavokPhysicsWithBindings } from '@babylonjs/havok'
import { Color3 } from '@babylonjs/core'

// build error that 'window is not defined'
// window.CANNON = CANNON;

const gravityVector = new Vector3(0, -9.81, 0)
const RADIUS = 5
const NUMBER_OF_BOXES = 8

const App: FC = () => {
const [fontsReady, setFontsReady] = useState(false)
const [HK, setHK] = useState<HavokPhysicsWithBindings>()

const faLoaded = useRef(false)
useEffect(() => {
if (document.fonts.check('16px FontAwesome') === false) {
document.fonts.load('16px FontAwesome').then(() => {
if (faLoaded.current !== true) {
faLoaded.current = true
setFontsReady(true)
}
})
} else if (faLoaded.current !== true) {
faLoaded.current = true
setFontsReady(true)
}
;(async () => {
setHK(await HavokPhysics())
})()
}, [])

return (
<div className="App">
<header className="App-header">
<Engine antialias={true} adaptToDeviceRatio={true} canvasId="sample-canvas">
{HK ? (
<Scene enablePhysics={[null, new HavokPlugin(false, HK)]}>
<arcRotateCamera
name="arc"
target={new Vector3(0, 1, 0)}
alpha={-Math.PI / 2}
beta={0.2 + Math.PI / 4}
wheelPrecision={50}
radius={14}
minZ={0.001}
lowerRadiusLimit={8}
upperRadiusLimit={20}
upperBetaLimit={Math.PI / 2}
/>
<hemisphericLight name="hemi" direction={new Vector3(0, -1, 0)} intensity={0.8} />
<directionalLight
name="shadow-light"
setDirectionToTarget={[Vector3.Zero()]}
direction={Vector3.Zero()}
position={new Vector3(-40, 30, -40)}
intensity={0.4}
shadowMinZ={1}
shadowMaxZ={2500}
>
<shadowGenerator
mapSize={1024}
useBlurExponentialShadowMap={true}
blurKernel={32}
darkness={0.8}
forceBackFacesOnly={true}
depthScale={100}
shadowCastChildren
>
{Array.from(new Array(NUMBER_OF_BOXES), (_, index) => index).map((x) => (
<BouncySphere
key={x}
name={x.toFixed()}
fontsReady={fontsReady}
position={
new Vector3(
Math.cos(((2 * Math.PI) / NUMBER_OF_BOXES) * x) * RADIUS,
3,
Math.sin(((2 * Math.PI) / NUMBER_OF_BOXES) * x) * RADIUS
)
}
color={
new Color3(
Math.abs(x - NUMBER_OF_BOXES / 2) / 10,
Math.abs(x - NUMBER_OF_BOXES / 2) / 10,
Math.abs(x - NUMBER_OF_BOXES / 2) / 10
)
}
/>
))}
</shadowGenerator>
</directionalLight>

<ground name="ground1" width={24} height={24} subdivisions={2} receiveShadows={true}>
<physicsAggregate
type={PhysicsShapeType.BOX}
_options={{ mass: 0, restitution: 0.9 }}
/>
</ground>
<vrExperienceHelper
webVROptions={{ createDeviceOrientationCamera: false }}
enableInteractions={true}
/>
</Scene>
) : null}
</Engine>
</header>
</div>
)
}
export default App
18 changes: 18 additions & 0 deletions packages/static/content/examples/physics/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,24 @@
title: 'Physics'
---

# Physics v2

You can use the Havok plugin for physics v2

When you declare your physics aggregate you need to set the type and pass in the
appropriate options. Note the leading underscore due to how the babylon class
was created.

```jsx
<mesh ...>
<physicsAggregate type={PhysicsShapeType.BOX} _options={{ mass: 0, restitution: 0.9 }} />
</mesh>
```

[devtool:Physics2.tsx]

# Physics v1

You can use other supported libraries like AMMO.js - this example uses Cannon.

When you declare your physics impostor you need to set the type and pass in the
Expand Down
1 change: 1 addition & 0 deletions packages/static/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"@babylonjs/core": "^6.25.0",
"@babylonjs/gui": "^6.25.0",
"@babylonjs/gui-editor": "^6.25.0",
"@babylonjs/havok": "^1.2.1",
"@babylonjs/inspector": "^6.25.0",
"@babylonjs/loaders": "^6.25.0",
"@babylonjs/materials": "^6.25.0",
Expand Down

0 comments on commit b955f6d

Please sign in to comment.