
Three.js 0.166.0 & Rapier 0.13.1 を使って物理演算してみるテストその2
概要
前回からのつづきです。 ひきつづきThree.jsとRapierの連携のテストを行っています。 今回はRapierに用意されている、appulyImpulse、addForce、setTranslationといった関数を使用して、物理演算の対象を操作して移動させることができるようにしたり、その対象を衝突させたりしてみました。 ちなみに、物理演算による移動のテストだけを行ったコードのリストなので、地味&同じような画面サムネイルが延々と続きますw。
関数の使い方は基本的には本家サイトのドキュメントを参考にしました。 ドキュメントを読むだけではいまいち実際の動きをイメージできなかったので、appulyImpulse、addForce、setTranslationといった関数を実際に動かしてテストしてみたのが今回のコードのリストです。
操作対象となる3Dモデルは、Three.jsによる見た目の Box と Rapierの物理演算用 Cuboid のペアです。 立方体になります。
操作対象の(物理演算による)衝突対象となる3Dモデルは、Three.jsによる見た目の Sphere と Rapierの物理演算用 Ball のペアです。 球体になります。
黄色い地面としているのは、Three.jsによる見た目の Box と Rapierの動かない(fixedな) Cuboid のペアです。
Practice 24 Box Move By applyImpulse 01
Three.js 0.166.0 & Rapier 0.13.1 Practice 24 Box Move By applyImpulse 01

appulyImpulseを使用して操作対象のCudoid(とそれに連動するBox)を移動させています。
最初に表示される画面の向きで見ているとして、「Forward」ボタン押下でappulyImpulseによりCuboidに画面の奥側への力が、「Backwrard」ボタン押下でappulyImpulseによりCuboidに画面の手前側への力が、かかるようになっています。
「Left」「Right」ボタン押下では同じように左右に動くようにappulyImpulseで力がかかるようにしていますが、横殴りされてそのまま横へスライドする感じの動きになっています。 このあたりは、左右回転による方向変更の機能に修正していきます。
また、appulyImpulseを適応するにはボタンを何度も押さなければならない状態です。 これは、ボタンを押しっぱなしの状態でも機能するように修正していきます。
Practice24でのボタン押下時に appulyImpulse を Cubooid に適応しているコードは以下になります。
// buttons to apply impulse to physical cube body (cuboid)
document.querySelector('#leftButton').onclick = function() {
cubeBody.applyImpulse(new RAPIER.Vector3(-2, 0, 0), true)
}
document.querySelector('#forwardButton').onclick = function() {
cubeBody.applyImpulse(new RAPIER.Vector3(0, 0, -2), true)
}
document.querySelector('#backwardButton').onclick = function() {
cubeBody.applyImpulse(new RAPIER.Vector3(0, 0, 2), true)
}
document.querySelector('#rightButton').onclick = function() {
cubeBody.applyImpulse(new RAPIER.Vector3(2, 0, 0), true)
}
Practice 25 Box Move By applyImpulse 02
Three.js 0.166.0 & Rapier 0.13.1 Practice 25 Box Move By applyImpulse 02

ひきつづきappulyImpulseを使用しつつ、「Left」「Right」ボタン押下時にCuboidがふつうに左右回転するようにしてみました。 また、それにあわせて「Forward」「Backward」ボタン押下時も操作対象の向いている方向に沿って進むように修正しました。
ボタンはまだ押下ごとに少しづつappulyImpulseを適用する状態(ボタンを押しっぱなしでappulyImpulseを適用することができない状態)です。
Practice25でのボタン押下時に appulyImpulse を Cubooid に適応しているコードは以下になります。
// buttons to apply impulse to physical cube body (cuboid)
document.querySelector('#leftButton').onclick = function() {
cubeMesh.rotation.y = cubeMesh.rotation.y + Math.PI/90
cubeBody.setRotation( new RAPIER.Quaternion( cubeMesh.quaternion.x, cubeMesh.quaternion.y, cubeMesh.quaternion.z, cubeMesh.quaternion.w), true )
}
document.querySelector('#forwardButton').onclick = function() {
const vector = new THREE.Vector3( 0, 0, -1 )
vector.applyQuaternion( cubeMesh.quaternion )
let directVector = new RAPIER.Vector3( vector.x, vector.y, vector.z)
cubeBody.applyImpulse( directVector, true )
}
document.querySelector('#backwardButton').onclick = function() {
//cubeBody.applyImpulse(new RAPIER.Vector3(0, 0, 2), true)
const vector = new THREE.Vector3( 0, 0, 1 )
vector.applyQuaternion( cubeMesh.quaternion )
let directVector = new RAPIER.Vector3( vector.x, vector.y, vector.z)
cubeBody.applyImpulse( directVector, true )
}
document.querySelector('#rightButton').onclick = function() {
cubeMesh.rotation.y = cubeMesh.rotation.y - Math.PI/90
cubeBody.setRotation( new RAPIER.Quaternion( cubeMesh.quaternion.x, cubeMesh.quaternion.y, cubeMesh.quaternion.z, cubeMesh.quaternion.w), true )
}
ボタン押下時の Box と Cuboid の動きの連携のために以下のサイトを参考にさせていただきました
https://github.com/yomotsu/rapier-tryout/blob/main/3_vehicle-controls/src/main.ts
https://github.com/pmndrs/react-three-rapier
Colliders
https://rapier.rs/docs/user_guides/javascript/colliders/
Quaternion
https://threejs.org/docs/#api/en/math/Quaternion
Practice 26 Box Move By applyImpulse 03
Three.js 0.166.0 & Rapier 0.13.1 Practice 26 Box Move By applyImpulse 03

ひきつづきappulyImpulseを使用しています。 「Forward」「Backward」「Left」「Right」ボタンを押しっぱなしにしても、それらボタンによる前進、後退、回転、の処理が続くように修正しました。 また操作対象の立方体がぶつかる対象となる球体もこのPracticeから置くようにしました。
機能に合わせて以下のあたりのコードを修正しました。
ボタンが押されている状態を設定するコードです。
// change the state of button when button down or up
document.querySelector('#leftButton').onmousedown = function() {
leftRotation = true
}
document.querySelector('#leftButton').onmouseup = function() {
leftRotation = false
}
document.querySelector('#forwardButton').onmousedown = function() {
forward = true
}
document.querySelector('#forwardButton').onmouseup = function() {
forward = false
}
document.querySelector('#backwardButton').onmousedown = function() {
backward = true
}
document.querySelector('#backwardButton').onmouseup = function() {
backward = false
}
document.querySelector('#rightButton').onmousedown = function() {
rightRotation = true
}
document.querySelector('#rightButton').onmouseup = function() {
rightRotation = false
}
animamte()関数内で、ボタンが押されている状態での処理を行ってます。 途中で自分でもコードの内容についていきづらくなったのか、コード内容についてのコメントを頑張って残しているようです、昔の自分w。
function animate() {
requestAnimationFrame(animate)
delta = clock.getDelta()
world.timestep = Math.min(delta, 0.01)
world.step()
// when one of buttons is pressed, apply impulse to physical cube body (cuboid)
// state of button is changed when button down or up
if ( leftRotation ) {
// cubeMesh.rotation.y = cubeMesh.rotation.y + Math.PI/90
// cubeBody.setRotation( new RAPIER.Quaternion( cubeMesh.quaternion.x, cubeMesh.quaternion.y, cubeMesh.quaternion.z, cubeMesh.quaternion.w), true )
//【THREE.js】Quaternionでローカル座標の回転を取り扱う
// https://qiita.com/Guvalif/items/ab0c847390adbb8e4a06
// → 回転操作について参考にさせていただきました
// 1. 回転させたいObjectのQuaternionを取得する
const quaternion = cubeMesh.quaternion
// 2. 回転を加えるためのQuaternionを作成する
const target = new THREE.Quaternion()
const axis = new THREE.Vector3(0, 1, 0).normalize()
target.setFromAxisAngle(axis, Math.PI / 90)
// 3. 回転させる
quaternion.multiply(target)
cubeBody.setRotation( new RAPIER.Quaternion( cubeMesh.quaternion.x, cubeMesh.quaternion.y, cubeMesh.quaternion.z, cubeMesh.quaternion.w), true )
}
if ( forward ) {
const vector = new THREE.Vector3( 0, 0, -0.3 )
vector.applyQuaternion( cubeMesh.quaternion )
let directVector = new RAPIER.Vector3( vector.x, vector.y, vector.z)
cubeBody.applyImpulse( directVector, true )
}
if ( backward ) {
const vector = new THREE.Vector3( 0, 0, 0.3 )
vector.applyQuaternion( cubeMesh.quaternion )
let directVector = new RAPIER.Vector3( vector.x, vector.y, vector.z)
cubeBody.applyImpulse( directVector, true )
}
if ( rightRotation ) {
// cubeMesh.rotation.y = cubeMesh.rotation.y - Math.PI/90
// cubeBody.setRotation( new RAPIER.Quaternion( cubeMesh.quaternion.x, cubeMesh.quaternion.y, cubeMesh.quaternion.z, cubeMesh.quaternion.w), true )
// 1. 回転させたいObjectのQuaternionを取得する
const quaternion = cubeMesh.quaternion
// 2. 回転を加えるためのQuaternionを作成する
const target = new THREE.Quaternion()
const axis = new THREE.Vector3(0, 1, 0).normalize()
target.setFromAxisAngle(axis, - Math.PI / 90)
// 3. 回転させる
quaternion.multiply(target)
cubeBody.setRotation( new RAPIER.Quaternion( cubeMesh.quaternion.x, cubeMesh.quaternion.y, cubeMesh.quaternion.z, cubeMesh.quaternion.w), true )
}
cubeMesh.position.copy(cubeBody.translation())
cubeMesh.quaternion.copy(cubeBody.rotation())
sphereMesh.position.copy(sphereBody.translation())
sphereMesh.quaternion.copy(sphereBody.rotation())
rapierDebugRenderer.update()
controls.update()
renderer.render(scene, camera)
}
Practice 27 Box Move By addForce
Three.js 0.166.0 & Rapier 0.13.1 Practice 27 Box Move By addForce

操作対象を操作するために使用するRapierの関数を appulyImpulse から addForce 使用へと変更してみたものです。 addForce では「Forward」「Backward」ボタンを押してから操作対象の加速までの時間が若干かかってしまうようでした。 他にもresetForceの設定も必要だったりと、このときの自分のやりたいことからは addForce はあまり使い勝手がよくなさそうでした。
animate()内のコードは以下のようになります。
function animate() {
requestAnimationFrame(animate)
delta = clock.getDelta()
world.timestep = Math.min(delta, 0.01)
world.step()
// 参考サイト
// Rigid-bodies
// https://rapier.rs/docs/user_guides/javascript/rigid_bodies
//
// when one of buttons is pressed, rotate or add force to physical cube body (cuboid)
// state of button is changed when button down or up
if ( leftRotation ) {
//【THREE.js】Quaternionでローカル座標の回転を取り扱う
// https://qiita.com/Guvalif/items/ab0c847390adbb8e4a06
// → 回転操作について参考にさせていただきました
// 1. 回転させたいObjectのQuaternionを取得する
const quaternion = cubeMesh.quaternion
// 2. 回転を加えるためのQuaternionを作成する
const target = new THREE.Quaternion()
const axis = new THREE.Vector3(0, 1, 0).normalize()
target.setFromAxisAngle(axis, Math.PI / 90)
// 3. 回転させる
quaternion.multiply(target)
cubeBody.setRotation( new RAPIER.Quaternion( cubeMesh.quaternion.x, cubeMesh.quaternion.y, cubeMesh.quaternion.z, cubeMesh.quaternion.w), true )
}
if ( forward ) {
const vector = new THREE.Vector3( 0, 0, -0.3 )
vector.applyQuaternion( cubeMesh.quaternion )
let directVector = new RAPIER.Vector3( vector.x, vector.y, vector.z)
//cubeBody.applyImpulse( directVector, true )
cubeBody.addForce( directVector, true )
}
if ( backward ) {
const vector = new THREE.Vector3( 0, 0, 0.3 )
vector.applyQuaternion( cubeMesh.quaternion )
let directVector = new RAPIER.Vector3( vector.x, vector.y, vector.z)
//cubeBody.applyImpulse( directVector, true )
cubeBody.addForce( directVector, true )
}
if ( !forward && !backward ) {
cubeBody.resetForces( true )
}
if ( rightRotation ) {
// 1. 回転させたいObjectのQuaternionを取得する
const quaternion = cubeMesh.quaternion
// 2. 回転を加えるためのQuaternionを作成する
const target = new THREE.Quaternion()
const axis = new THREE.Vector3(0, 1, 0).normalize()
target.setFromAxisAngle(axis, - Math.PI / 90)
// 3. 回転させる
quaternion.multiply(target)
cubeBody.setRotation( new RAPIER.Quaternion( cubeMesh.quaternion.x, cubeMesh.quaternion.y, cubeMesh.quaternion.z, cubeMesh.quaternion.w), true )
}
cubeMesh.position.copy(cubeBody.translation())
cubeMesh.quaternion.copy(cubeBody.rotation())
sphereMesh.position.copy(sphereBody.translation())
sphereMesh.quaternion.copy(sphereBody.rotation())
rapierDebugRenderer.update()
controls.update()
renderer.render(scene, camera)
}
このPractice27以降のコードでは、基本的に以下の本家サイトドキュメントを参考にさせていただきました。
Practice 28 Box Move By setTranslation
Three.js 0.166.0 & Rapier 0.13.1 Practice 28 Box Move By setTranslation

Practice28では操作対象を操作するために使用するRapierの関数を setTranslation へ変更してみました。 setTranslationでは座標を指定して、そこに操作対象を直接移動させる関数のようです。
公式ではsetTranslationを普通に使用すると操作対象がワープしたように見える場合があるのであまりお勧めされていないようでしたが、自分的には移動距離を小さめに調整すればわりといい感じの動きを表現できると感じました。 操作対象の移動開始までの加速途中のインターバルが存在しなくて、移動時の速度も安定しているように自分には見えました。
ちなみに、ものは試しにと少し大きめの移動距離を設定すると、漫画・アニメなんかのキャラクタの高速移動のような見た目にw。 さらに移動距離を大きくすると、確かにワープのような動きにw。 一度に移動できる座標の間隔の設定が重要そうです。
animate()内でsetTranslationを使用するコードは以下のようになっています。 setTranslationの使用感をテストするためにあれこれ試したコードのコメントアウトでそのまま残っていますがw。
function animate() {
requestAnimationFrame(animate)
delta = clock.getDelta()
world.timestep = Math.min(delta, 0.01)
world.step()
// 参考サイト
// Rigid-bodies
// https://rapier.rs/docs/user_guides/javascript/rigid_bodies
//
// when one of buttons is pressed, rotate or add force to physical cube body (cuboid)
// state of button is changed when button down or up
if ( leftRotation ) {
//【THREE.js】Quaternionでローカル座標の回転を取り扱う
// https://qiita.com/Guvalif/items/ab0c847390adbb8e4a06
// → 回転操作について参考にさせていただきました
// 1. 回転させたいObjectのQuaternionを取得する
const quaternion = cubeMesh.quaternion
// 2. 回転を加えるためのQuaternionを作成する
const target = new THREE.Quaternion()
const axis = new THREE.Vector3(0, 1, 0).normalize()
target.setFromAxisAngle(axis, Math.PI / 90)
// 3. 回転させる
quaternion.multiply(target)
cubeBody.setRotation( new RAPIER.Quaternion( cubeMesh.quaternion.x, cubeMesh.quaternion.y, cubeMesh.quaternion.z, cubeMesh.quaternion.w), true )
}
if ( forward ) {
const vector = new THREE.Vector3( 0, 0, -0.3 )
vector.applyQuaternion( cubeMesh.quaternion )
//let directVector = new RAPIER.Vector3( vector.x, vector.y, vector.z)
let directVector = vector.setLength(0.03)
//cubeBody.applyImpulse( directVector, true )
//cubeBody.addForce( directVector, true )
// test setTranslation
//cubeBody.setTranslation({ x: 0.0, y: 5.0, z: 1.0 }, true)
//cubeBody.setTranslation({ x: 1.0, y: 0.0, z: 2.0 }, true)
//cubeBody.setTranslation({ x: vector.x, y: vector.y, z: vector.z }, true)
//cubeBody.setTranslation({ x: cubeMesh.position.x + vector.x, y: cubeMesh.position.y + vector.y, z: cubeMesh.position.z + vector.z }, true)
cubeBody.setTranslation({ x: cubeMesh.position.x + directVector.x, y: cubeMesh.position.y + directVector.y, z: cubeMesh.position.z + directVector.z }, true)
}
if ( backward ) {
const vector = new THREE.Vector3( 0, 0, 0.3 )
vector.applyQuaternion( cubeMesh.quaternion )
//let directVector = new RAPIER.Vector3( vector.x, vector.y, vector.z)
let directVector = vector.setLength(0.03)
//cubeBody.applyImpulse( directVector, true )
//cubeBody.addForce( directVector, true )
cubeBody.setTranslation({ x: cubeMesh.position.x + directVector.x, y: cubeMesh.position.y + directVector.y, z: cubeMesh.position.z + directVector.z }, true)
}
if ( rightRotation ) {
// 1. 回転させたいObjectのQuaternionを取得する
const quaternion = cubeMesh.quaternion
// 2. 回転を加えるためのQuaternionを作成する
const target = new THREE.Quaternion()
const axis = new THREE.Vector3(0, 1, 0).normalize()
target.setFromAxisAngle(axis, - Math.PI / 90)
// 3. 回転させる
quaternion.multiply(target)
cubeBody.setRotation( new RAPIER.Quaternion( cubeMesh.quaternion.x, cubeMesh.quaternion.y, cubeMesh.quaternion.z, cubeMesh.quaternion.w), true )
}
cubeMesh.position.copy(cubeBody.translation())
cubeMesh.quaternion.copy(cubeBody.rotation())
sphereMesh.position.copy(sphereBody.translation())
sphereMesh.quaternion.copy(sphereBody.rotation())
rapierDebugRenderer.update()
controls.update()
renderer.render(scene, camera)
}
Practice 29 Kinematic Box Move By setTranslation
Three.js 0.166.0 & Rapier 0.13.1 Practice 29 Kinematic Box Move By setTranslation

Practice28で使用したsetTranslationは本来はKinematicの性質をもつ操作対象とともに使用されるもののようです。 そのKinematiceをテスト的に試してみました。 ちなみにKinematiceとsetTranslationのセットは(重力がかかる物理演算の対象物とは別の動きをする)ゲーム内のエレベーターのようなもので使われるとどこかで見かけた、ような気がします(うろ覚えw)。
KinematicとsetTranslationを使用した操作対象は、物理演算の対象となっているもの(ここでは Ball )とは衝突などの演算を行いますが、重力を無視して、下の黄色い地面を越えても落下せずにずっと浮いているようになりました。 これがエレベーターのなどの動きのために使われるのでしょうか? 自分はいまいち使い道思いつきませんでした。 浮遊物とかの動きの設定によい?
Practice 29_02 Kinematic Box Move By setTranslation
Three.js 0.166.0 & Rapier 0.13.1 Practice 29_02 Kinematic Box Move By setTranslation

さらにKinematicの機能を試してみました。 Kinematic設定されたものは、fixedに設定されたものとは物理演算しない的な記述もみかけたので、今度はわざとに地面の黄色い部分にめりこませてみました。 たしかに衝突の物理演算ガン無視で自由に動けるようでしたw。 土中のモンスターとかの設定に、いい、のか? 空中を歩けて地面もすり抜ける特殊な神的キャラをゲーム内で設定時に使用とか?
Practice 29_03 Kinematic Box Move By setTranslation
Three.js 0.166.0 & Rapier 0.13.1 Practice 29_03 Kinematic Box Move By setTranslation

さらにKinematicの機能を試しているようでした。 が、「いるようでした」と書いている通り、自分でも何も試したのか全く覚えていませんw。 最近コードの記録noteを作成するとよく出てくるやつですw。 いつものように、とりあえず残しておきますw。
自分にはいまいち使いどころが想像できなかったKinematicでしたが、こちらの動画
three.js & rapier3D - Character Terrain Movement
のようにKinematicを使いこなせば、Terrainなフィールドの表現もできるようです。
が、とりあえず自分には無理そうでしたw。
Practice 30 Kinematic Box Move By velocity
Three.js 0.166.0 & Rapier 0.13.1 Practice 30 Kinematic Box Move By velocity

Practice30からはsetTranslationのかわりにvelocityを設定することで操作対象のCuboidを動かすようにしてみました。
setLinvelという関数でCuboidの(角度含む)進行速度を設定しています。 setLinvelの前あたりにコメントアウトしたコードが大量に残っているのは、それまでに使用していた、applyImpulseやaddForceとの書き方の比較、テスト用に使用したvelocity系関数?の残骸等です。
animate関数は以下のようになります。
function animate() {
requestAnimationFrame(animate)
delta = clock.getDelta()
world.timestep = Math.min(delta, 0.01)
world.step()
// 参考サイト
// Rigid-bodies
// https://rapier.rs/docs/user_guides/javascript/rigid_bodies
//
// when one of buttons is pressed, rotate or add force to physical cube body (cuboid)
// state of button is changed when button down or up
if ( leftRotation ) {
//【THREE.js】Quaternionでローカル座標の回転を取り扱う
// https://qiita.com/Guvalif/items/ab0c847390adbb8e4a06
// → 回転操作について参考にさせていただきました
// 1. 回転させたいObjectのQuaternionを取得する
const quaternion = cubeMesh.quaternion
// 2. 回転を加えるためのQuaternionを作成する
const target = new THREE.Quaternion()
const axis = new THREE.Vector3(0, 1, 0).normalize()
target.setFromAxisAngle(axis, Math.PI / 90)
// 3. 回転させる
quaternion.multiply(target)
cubeBody.setRotation( new RAPIER.Quaternion( cubeMesh.quaternion.x, cubeMesh.quaternion.y, cubeMesh.quaternion.z, cubeMesh.quaternion.w), true )
}
if ( forward ) {
const vector = new THREE.Vector3( 0, 0, -3 )
vector.applyQuaternion( cubeMesh.quaternion )
let directVector = new RAPIER.Vector3( vector.x, vector.y, vector.z)
//cubeBody.applyImpulse( directVector, true )
//cubeBody.addForce( directVector, true )
// to test moving by velocity
//cubeBody.setLinvel({ x: 1.0, y: 3.0, z: 4.0 }, true)
//cubeBody.setAngvel({ x: 3.0, y: 0.0, z: 0.0 }, true)
cubeBody.setLinvel({ x: vector.x, y: vector.y, z: vector.z }, true)
}
if ( backward ) {
const vector = new THREE.Vector3( 0, 0, 3 )
vector.applyQuaternion( cubeMesh.quaternion )
let directVector = new RAPIER.Vector3( vector.x, vector.y, vector.z)
//cubeBody.applyImpulse( directVector, true )
//cubeBody.addForce( directVector, true )
cubeBody.setLinvel({ x: vector.x, y: vector.y, z: vector.z }, true)
}
if ( !forward && !backward ) {
cubeBody.resetForces( true )
// to test moving by velocity
//cubeBody.setLinvel({ x: 0, y: 0, z: 0 }, true)
//cubeBody.setAngvel({ x: 0, y: 0, z: 0 }, true)
cubeBody.setLinvel({ x: 0, y: 0, z: 0 }, true)
}
if ( rightRotation ) {
// 1. 回転させたいObjectのQuaternionを取得する
const quaternion = cubeMesh.quaternion
// 2. 回転を加えるためのQuaternionを作成する
const target = new THREE.Quaternion()
const axis = new THREE.Vector3(0, 1, 0).normalize()
target.setFromAxisAngle(axis, - Math.PI / 90)
// 3. 回転させる
quaternion.multiply(target)
cubeBody.setRotation( new RAPIER.Quaternion( cubeMesh.quaternion.x, cubeMesh.quaternion.y, cubeMesh.quaternion.z, cubeMesh.quaternion.w), true )
}
cubeMesh.position.copy(cubeBody.translation())
cubeMesh.quaternion.copy(cubeBody.rotation())
sphereMesh.position.copy(sphereBody.translation())
sphereMesh.quaternion.copy(sphereBody.rotation())
rapierDebugRenderer.update()
controls.update()
renderer.render(scene, camera)
}
Practice 30_02 Kinematic Box Move By velocity
Three.js 0.166.0 & Rapier 0.13.1 Practice 30_02 Kinematic Box Move By velocity

Practice30からひきつづきPractice31でもvelocityの使い方を試しています。 setAngvelという操作対象の角度を簡単に変更できる関数を使用しました。 そのsetAngvelを使用すると、角度計算のコードをかなりすっきりとさせることができました。
その結果コード全体としては、setAngvel関数でCuboidの角度を、setLinvel関数でCuboidの(角度含む)進行速度を、設定しています。 setAngvelとsetLinvelはそれぞれ、set Angle velocity と set Line velocity の略だと想像しますが、velocityが英語の「速度」なので、setAngvelは角速度を設定、setLinevelは直線速度を設定、といったイメージの関数名でしょうか。
animate関数は以下のようになります。
function animate() {
requestAnimationFrame(animate)
delta = clock.getDelta()
world.timestep = Math.min(delta, 0.01)
world.step()
// 参考サイト
// Rigid-bodies
// https://rapier.rs/docs/user_guides/javascript/rigid_bodies
//
// when one of buttons is pressed, rotate or add force to physical cube body (cuboid)
// state of button is changed when button down or up
if ( leftRotation ) {
cubeBody.setAngvel({ x: 0.0, y: 3.0, z: 0.0 }, true)
}
if ( forward ) {
const vector = new THREE.Vector3( 0, 0, -3 )
vector.applyQuaternion( cubeMesh.quaternion )
cubeBody.setLinvel({ x: vector.x, y: vector.y, z: vector.z }, true)
}
if ( backward ) {
const vector = new THREE.Vector3( 0, 0, 3 )
vector.applyQuaternion( cubeMesh.quaternion )
cubeBody.setLinvel({ x: vector.x, y: vector.y, z: vector.z }, true)
}
if ( rightRotation ) {
cubeBody.setAngvel({ x: 0.0, y: -3.0, z: 0.0 }, true)
}
if ( !forward && !backward ) {
cubeBody.setLinvel({ x: 0, y: 0, z: 0 }, true)
}
if ( !leftRotation && !rightRotation ) {
cubeBody.setAngvel({ x: 0, y: 0, z: 0 }, true)
}
cubeMesh.position.copy(cubeBody.translation())
cubeMesh.quaternion.copy(cubeBody.rotation())
sphereMesh.position.copy(sphereBody.translation())
sphereMesh.quaternion.copy(sphereBody.rotation())
rapierDebugRenderer.update()
controls.update()
renderer.render(scene, camera)
}
Practice 30_03 Kinematic Box Move By velocity
Three.js 0.166.0 & Rapier 0.13.1 Practice 30_03 Kinematic Box Move By velocity

せっかくKinematicを使用しているので、「Up」「Down」といったボタンを追加して空中散歩のようなことができるかふざけて作成してみたコードですw。 物理法則(主に重力)ガン無視して空中散歩できるようですw。 ついでに下の黄色の地面をすり抜けることもできますw。 ゲームで神的キャラ製作に大活躍の機能???w
「Up」「Down」ボタンに関するものを追加したうえでの、animate関数は以下になります。
function animate() {
requestAnimationFrame(animate)
delta = clock.getDelta()
world.timestep = Math.min(delta, 0.01)
world.step()
// 参考サイト
// Rigid-bodies
// https://rapier.rs/docs/user_guides/javascript/rigid_bodies
//
// when one of buttons is pressed, rotate or add force to physical cube body (cuboid)
// state of button is changed when button down or up
if ( leftRotation ) {
cubeBody.setAngvel({ x: 0.0, y: 3.0, z: 0.0 }, true)
}
if ( forward ) {
const vector = new THREE.Vector3( 0, 0, -3 )
vector.applyQuaternion( cubeMesh.quaternion )
cubeBody.setLinvel({ x: vector.x, y: vector.y, z: vector.z }, true)
}
if ( backward ) {
const vector = new THREE.Vector3( 0, 0, 3 )
vector.applyQuaternion( cubeMesh.quaternion )
cubeBody.setLinvel({ x: vector.x, y: vector.y, z: vector.z }, true)
}
if ( rightRotation ) {
cubeBody.setAngvel({ x: 0.0, y: -3.0, z: 0.0 }, true)
}
if ( up ) {
cubeBody.setLinvel({ x: 0, y: 3, z: 0 }, true)
}
if ( down ) {
cubeBody.setLinvel({ x: 0, y: -3, z: 0 }, true)
}
if ( ( !forward && !backward ) && ( !up && !down ) ) {
cubeBody.setLinvel({ x: 0, y: 0, z: 0 }, true)
}
if ( !leftRotation && !rightRotation ) {
cubeBody.setAngvel({ x: 0, y: 0, z: 0 }, true)
}
cubeMesh.position.copy(cubeBody.translation())
cubeMesh.quaternion.copy(cubeBody.rotation())
sphereMesh.position.copy(sphereBody.translation())
sphereMesh.quaternion.copy(sphereBody.rotation())
rapierDebugRenderer.update()
controls.update()
renderer.render(scene, camera)
}
Practice 31 Box Move By velocity
Three.js 0.166.0 & Rapier 0.13.1 Practice 31 Box Move By velocity

最後にvelocityによる操作は残したままで、Kinematicな?操作対象を普通のBox&Cuboidに変更しました。 これで(Kinematicでない)普通の?物理演算をvelocityで行う状態になりました。 自分としてはvelocityによる「操作」なかなか使えそうな感じでした。 velocityによる操作なら回転しながらの進行もできるよう(setTranslationではできなさそう)。
このPractice31までの実験で、個人的にはこのvelocityとsetTranslationによる「操作対象の移動」が使い勝手がよさそうでした。
この後はそれらの「操作対象の移動」と前回noteでの3Dモデルの表示を組み合わせてのThree.jsとRapierとの連携を試してみたいと思います。