質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Three.js

Three.jsはWebGLをサポートしているJavaScriptの3D描画用ライブラリです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

2回答

526閲覧

threeJS、Planeの上にSphere(球体)をぴったり乗せる方法

SaintKnowledge

総合スコア368

Three.js

Three.jsはWebGLをサポートしているJavaScriptの3D描画用ライブラリです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2017/12/17 10:40

COBOLer & PHPerですが、必要上、Javascriptもゴリゴリ書く方です。

現在、ThreeJSに触れてます。PlaneやSphere(球体)の描画自体は問題無く動作しています。OrbitControlsでグリグリ回すのも大丈夫です。

一つ分からないのが、適当な座標にPlaneと球体を配置するのではなく、Planeの座標上ぴったりに球体を置きたいのですが、方法が分かりません。将来的には、plane.verticesで頂点を書き換えて傾斜を付けたいので、どの位置に球体を置いてもPlane上にぴったりくっつけたいのですが、試行錯誤してもどうしても球体が少し埋まったような見栄えになったり、潜った感じになったり浮いた感じになったりします。

ぴったり上に乗っている、Planeの傾斜に正しく沿っている、という状況がわかりづらいのですが、方法や確認方法をご存知の方はいらっしゃいませんでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

自己解決

結果的に、CANNON.JSと組み合わせて、いい具合に跳ねない位置にy値を合わせることで、何とかしました。
いまいち納得いかない感じではありますが。。

投稿2017/12/25 09:15

SaintKnowledge

総合スコア368

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

球体ということですので、raycaster.intersectObject が使えそうです。

https://threejs.org/docs/#api/core/Raycaster

このデモが近そうと思いますが、どうでしょう
https://threejs.org/examples/#webgl_interactive_raycasting_points

具体的なステップとしては、
1・傾斜したplaneの外側に、球を置く基準となる1点を用意する。球の中央の値でも可
2・その点から、planeの中心に対して、intersectObjectを実行。
3・返り値に対して球をセットする

var basePos = new THREE.Vector3(// 省略。球の中心地点とする); var planeCenter = new THREE.Vector3(// 省略。planeの中心地点とする。); var ballToPlane = basePos.clone().sub(planeCenter).normalize(); // 球の中心から板の中心に向かうベクトルを作成し、さらに正規化 var ray = new THREE.Raycaster(basePos, ballToPlane); // ボールの位置から板に向かうrayを作成 var hits = ray.intersectObject(plane); // rayとplaneとの衝突を検知 if(hits && hits.length > 0){ // 衝突点にそのままボールの中央をセットしてしまうとめりこむので、ボールの半径分外側に移動させる var addPos = ballToPlane.multiply(-1).multiply(ballRadius); // sphereを作ったときに使った半径があれば使いまわせます var ballPos = hits[0].point.clone().add(addPos); //衝突検出した値と、上のめりこみ防止用の値を足す ball.Pos.copy(ballPos); //sphereの位置にセットして終了 }

投稿2017/12/17 12:56

adrs2002

総合スコア203

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

SaintKnowledge

2017/12/17 14:15 編集

詳細にありがとうございます。 うまく衝突判断が出来ないみたいで、hitsに引っかからず、Vector3の使い方が悪いのかも。。イベント系言語がちょっと苦手なもので。。 new THREE.Vector3(sphere.position.x, sphere.position.y, sphere.position.z); *このやり方では、球sphereの中心では無いですかね?
adrs2002

2017/12/17 14:21

sphereが、SphereGeometryから作ったものであれば、positionはsphereの中心であっています。 取れない原因となると…もしかしたら、 ``` var hits = ray.intersectObject(plane, true); ``` これで取れたりするかもしれません(子階層チェック)
SaintKnowledge

2017/12/17 15:26 編集

何度もありがとうございます。 なんか、うまくいかないです。多分自分のやり方が悪いのかと思います。 plane、sphereともに、座標位置をx,y,zともに0、rotationも0、としても衝突判断していないよう。。以下の通りですが、お気付きの点があればと思います。。 var planeGeometry = new THREE.PlaneGeometry(100, 60, 16, 16); var planeMaterial = new THREE.MeshBasicMaterial({color: 0x1B5E20, wireframe:true}); var plane = new THREE.Mesh(planeGeometry, planeMaterial); plane.rotation.x = 0; plane.position.x = 0; plane.position.y = 0; plane.position.z = 0; scene.add(plane); // 実際はここで、planeGeometry.verticesを使って16のマス目に斜面を付けています。 var sphere = new THREE.Mesh(new THREE.SphereGeometry(1, 20, 20), new THREE.MeshLambertMaterial({ color: 0xffff00, Ambient: 0xffff00 })); sphere.position.x = 0; sphere.position.y = 0; sphere.position.z = 0; // scene addの前に、ご教示のロジックを追加。 var basePos = new THREE.Vector3(sphere.position.x, sphere.position.y, sphere.position.z); var planeCenter = new THREE.Vector3(plane.position.x, plane.position.y, plane.position.z); var ballToPlane = basePos.clone().sub(planeCenter).normalize(); // 球の中心から板の中心に向かうベクトルを作成し、さらに正規化 console.log(ballToPlane); var ray = new THREE.Raycaster(basePos, ballToPlane); // ボールの位置から板に向かうrayを作成 var hits = ray.intersectObject(plane, true); // rayとplaneとの衝突を検知 console.log(hits); if(hits && hits.length > 0){ // 衝突点にそのままボールの中央をセットしてしまうとめりこむので、ボールの半径分外側に移動させる var addPos = ballToPlane.multiply(-1).multiply(1); // sphereを作ったときに使った半径があれば使いまわせます var ballPos = hits[0].point.clone().add(addPos); //衝突検出した値と、上のめりこみ防止用の値を足す ball.Pos.copy(ballPos); //sphereの位置にセットして終了 console.log(ball.Pos.copy(ballPos)); } scene.add(sphere);
SaintKnowledge

2017/12/17 15:18

console.log(hits); にて、hits が空っぽ、になってしまいます。
adrs2002

2017/12/17 15:27

> plane、sphereともに、座標位置をx,y,zともに0、rotationも0 これがやりがちな、しかしやってはいけない部分です。 `Raycaster`は、ある点からある物体(面)に向けたベクトルにて衝突検出を行うため、この値でセットをしてしまうと長さゼロのベクトルになり、衝突を検出することができません。 また、申し訳ないことに、自分のコードも間違っていたようで、正しくは ``` var ballToPlane = planeCenter.clone().sub(basePos).normalize(); // 球の中心から板の中心に向かうベクトルを作成し、さらに正規化 ``` でした(ベクトルの方角が逆を向いていた) 貼り付けてもらったソースに上記の修正を加えたところ、衝突点が検出できることを確認しました。
SaintKnowledge

2017/12/17 15:54 編集

なるほど、指摘ありがとうございます。 平面での衝突判断はうまくいったようですが、planeGeometry.verticesで斜面(頂点の修正)を付けると、全く衝突しなくなりまして。。 自分でも調べてみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問