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

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

新規登録して質問してみよう
ただいま回答率
85.48%
HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

Three.js

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

Q&A

2回答

6710閲覧

[Three.js] raycasterがうまく動作しません。

NoMoreTroll

総合スコア6

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

Three.js

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

0グッド

0クリップ

投稿2017/08/18 00:54

###前提・実現したいこと
Three.jsで製作しています。
外部からLosderで3Dモデルを読み込んで、Raycasterを使って対象の任意の部位にクリックすることでマーカー的なオブジェを配置させたいです。
最終的には新たに配置されたオブジェをさらにクリックすることで外部ブラウザを開き、TXTなどのデータを格納させたいと思っています。

###発生している問題・質問
STLLoaderによる3Dモデルの読込やTrackBallcontrolsによるマウスでのカメラ操作までは成功しているのですが、表示されたモデルにいくらクリックしても何の反応もなく、Raycasterによるクリックイベントが確認できません。様々な解説ブログを参照しましたが自分のやっていることは見様見真似ばかりで、少しずつ詳細を調べながら学習してはいるのですが、未熟故にまだ解決できていません。
https://threejs.org/docs/#api/core/Raycaster
https://threejs.org/examples/?q=interactive#canvas_interactive_cubes
※やりたかったクリック動作がこのサンプルに近いものであるが、Canvas描画である必要はない(WebGL描画)

また、クリックイベントで生成したオブジェに個別で外部ファイルを添付あるいはリンクさせたいのですが、クリックから外部ブラウザを開くこともできますでしょうか?

###該当のソースコード
「Three.js(JavaScript,html)」

<!doctype html> <html> <head> <meta charset="utf-8" /> <title>3D_STLloader</title> <script src="three.min.js"></script> <script src="TrackballControls.js"></script> <script src="Detector.js"></script> </head> <body> <div> <input type="file" id="file" /> </div> <div id="view"></div> <script> //------------------------------------------------------------------ // Detecter.js if(!Detector.webgl) Detector.addGetWebGLMessage(); //------------------------------------------------------------------ // STL.js var loadStl = ( function () { var binaryVector3 = function (view, offset) { var v = new THREE.Vector3(); v.x = view.getFloat32(offset + 0, true); v.y = view.getFloat32(offset + 4, true); v.z = view.getFloat32(offset + 8, true); return v; }; var loadBinaryStl = function (buffer) { // binary STL var view = new DataView(buffer); var size = view.getUint32(80, true); var geometry = new THREE.Geometry(); var offset = 84; for (var i = 0; i < size; i++) { var normal = binaryVector3(view, offset); geometry.vertices.push(binaryVector3(view, offset + 12)); geometry.vertices.push(binaryVector3(view, offset + 24)); geometry.vertices.push(binaryVector3(view, offset + 36)); geometry.faces.push( new THREE.Face3(i * 3, i * 3 + 1, i * 3 + 2, normal)); offset += 4 * 3 * 4 + 2; } return geometry; }; var m2vec3 = function (match) { var v = new THREE.Vector3(); v.x = parseFloat(match[1]); v.y = parseFloat(match[2]); v.z = parseFloat(match[3]); return v; }; var toLines = function (array) { var lines = []; var h = 0; for (var i = 0; i < array.length; i++) { if (array[i] === 10) { var line = String.fromCharCode.apply( null, array.subarray(h, i)); lines.push(line); h = i + 1; } } lines.push(String.fromCharCode.apply(null, array.subarray(h))); return lines; } var loadTextStl = function (buffer) { var lines = toLines(new Uint8Array(buffer)); var index = 0; var scan = function (regexp) { while (lines[index].match(/^\s*$/)) index++; var r = lines[index].match(regexp); return r; }; var scanOk = function (regexp) { var r = scan(regexp); if (!r) throw new Error( "not text stl: " + regexp.toString() + "=> (line " + (index - 1) + ")" + "[" + lines[index-1] + "]"); index++; return r; } var facetReg = /^\s*facet\s+normal\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)/; var vertexReg = /^\s*vertex\s+([^s]+)\s+([^\s]+)\s+([^\s]+)/; var geometry = new THREE.Geometry(); scanOk(/^\s*solid\s(.*)/); while (!scan(/^\s*endsolid/)) { var normal = scanOk(facetReg); scanOk(/^\s*outer\s+loop/); var v1 = scanOk(vertexReg); var v2 = scanOk(vertexReg); var v3 = scanOk(vertexReg); scanOk(/\s*endloop/); scanOk(/\s*endfacet/); var base = geometry.vertices.length; geometry.vertices.push(m2vec3(v1)); geometry.vertices.push(m2vec3(v2)); geometry.vertices.push(m2vec3(v3)); geometry.faces.push( new THREE.Face3(base, base + 1, base + 2, m2vec3(normal))); } return geometry; }; return function (buffer) { try { //console.log("load as text stl"); return loadTextStl(buffer); } catch (ex) { console.log(ex); //console.log("load as binary stl"); return loadBinaryStl(buffer); } }; } )(); // -------------------------------------------------------------------- // Loader.js window.addEventListener( "load", function () { "use strict"; //var w = window.innerWidth, h = window.innerHight; var w = 1000, h = 800; // Renderer var renderer = new THREE.WebGLRenderer({antialias: true}); renderer.setSize(w, h); var view = document.getElementById("view"); view.appendChild(renderer.domElement); var camera = new THREE.PerspectiveCamera(40, w / h, 1, 10000); camera.position.set(0, -20, 3); //var controls = new THREE.OrbitControls(camera, view); var controls = new THREE.TrackballControls(camera, view); var scene = new THREE.Scene(); scene.add(new THREE.AmbientLight(0xffffff)); var light1 = new THREE.DirectionalLight(0xffffff); light1.position.set(0, 1000, -1000); scene.add(light1); var light2 = new THREE.DirectionalLight(0xffffff); light2.position.set(0, -1000, 1000); scene.add(light2); var material = new THREE.MeshPhysicalMaterial({ color: 0xff5533, specular: 0xcccccc, shininess: 200 /*color: 0x339900, ambient: 0x339900, specular: 0x030303 */ }); var object = new THREE.Mesh(new THREE.Geometry(), material); scene.add(object); var loop = function loop() { requestAnimationFrame(loop); //object.rotation.z += 0.05; controls.update(); renderer.clear(); renderer.render(scene, camera); }; loop(); // file load var openFile = function (file) { var reader = new FileReader(); reader.addEventListener("load", function (ev) { var buffer = ev.target.result; var geometry = loadStl(buffer); scene.remove(object); object = new THREE.Mesh(geometry, material); scene.add(object); }, false); reader.readAsArrayBuffer(file); }; // file input button var input = document.getElementById("file"); input.addEventListener("change", function (ev) { var file = ev.target.files[0]; openFile(file); }, false ); // dnd view.addEventListener("dragover", function (ev) { ev.stopPropagation(); ev.preventDefault(); ev.dataTransfer.dropEffect = "copy"; }, false ); view.addEventListener("drop", function (ev) { ev.stopPropagation(); ev.preventDefault(); var file = ev.dataTransfer.files[0]; openFile(file); }, false ); }, false ); //----------------------------------------------------- // mouse event //var objects = []; var particleMaterial; var PI2 = Math.PI * 2; particleMaterial = new THREE.SpriteCanvasMaterial( { color: 0xffffff, program: function( context ){ context.beginPath(); context.arc( 0, 0, 0.5, 0, PI2, true ); context.fill(); } } ); // --------------------- var raycaster = new THREE.Raycaster(); var mouse = new THREE.Vector2(); document.addEventListener('mousedown', onDocumentMouseDown, false); function onDocumentMouseDown( event ){ //event.preventDefault(); mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1; mouse.Y = - ( event.clientY / window.innerHeight ) * 2 + 1; raycaster.setFromCamera( mouse, camera ); var intersects = raycaster.intersectObject( object.children ); if( intersects.length > 0 ){ //if( var i=0; i < intersects.length; i++ ){ intersects[ 0 ].object.material.color.set( 0xffffff ); //intersects[ i ].object.material.color.set( 0xffffff ); var particle = new THREE.Sprite( particleMaterial ); particle.position.copy( intersects[ 0 ].point ); particle.scale.x = particle.scale.y = 16; scene.add( particle ); } } </script> </body> </html>

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

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

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

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

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

guest

回答2

0

javascript

1mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1; 2mouse.Y = - ( event.clientY / window.innerHeight ) * 2 + 1;

yは小文字である必要があります。

投稿2017/08/22 06:43

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

0

動かしていないのですが、ソースを見て気になるところが一点。

js

1var intersects = raycaster.intersectObject( object.children );

衝突を調べたいのは、「object」自体、ですよね?
であるならば、

js

1var intersects = raycaster.intersectObjects( scene.children ); // ←最後にsがついて複数形 2または 3var intersects = raycaster.intersectObject(object); // sなしでobject単体のみ

としたらどうなるでしょうか。

または、raycaster がしっかり作れているかどうかを調べるために、Chrome Dev Tools (F12押すと出るあれ) あたりで raycaster のベクトルや開始点を調べてみる必要があるでしょう。

投稿2017/08/18 14:02

adrs2002

総合スコア203

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

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

NoMoreTroll

2017/08/18 14:44 編集

返答ありがとうございます。 JavaScriptvar intersects = raycaster.intersectObjects( scene.children ); // ←最後にsがついて複数形 または var intersects = raycaster.intersectObject(object); // sなしでobject単体のみ 教えていただいたようにSceneでもやってみましたが変わらずですね… また、上記の単体・複数指定での試しは以前やってみましたが変化なしでした。誤った方向で修正したりで異常があったらページが開かれることすらないはず・・・と思っていたわけですが、HTML起動は問題なく行われているところです。 STLモデルを外部から読み込んできて表示まで出来ているのですが、現状ではクリックしても反応がない(TrackballControlsによるカメラワークは正常)状態ですね。 Toolsでも同様にRaycasterあたりを探っているのですが何かみつけることは出来ませんでした。エラーを吐いてるわけでもなく目先真っ暗です… 他のところで問題があるのでしょうか。
adrs2002

2017/08/20 11:06 編集

これも的外れな回答になってしまったら申し訳ないですが、 ```javascript var loadBinaryStl = function (buffer) { // binary STL var view = new DataView(buffer); var size = view.getUint32(80, true); var geometry = new THREE.Geometry(); var offset = 84; for (var i = 0; i < size; i++) { var normal = binaryVector3(view, offset); geometry.vertices.push(binaryVector3(view, offset + 12)); geometry.vertices.push(binaryVector3(view, offset + 24)); geometry.vertices.push(binaryVector3(view, offset + 36)); geometry.faces.push( new THREE.Face3(i * 3, i * 3 + 1, i * 3 + 2, normal)); offset += 4 * 3 * 4 + 2; } geometry.computeBoundingBox(); geometry.computeBoundingSphere(); return geometry; }; ``` こんな風に、最後に computeBoundingBox を呼ぶようにしたら、何か変わるかもしれません(というのも、rayCasterの中で BoundingBox を使っているので。 (もしかしたら、 geometry → mesh にしたときに、自動的に生成していたような気がしなくもないのですが、念のため)
NoMoreTroll

2017/08/20 15:28

引き続き確認していただきありがとうございます。 教えていただいた内容で試しましたが、変化ありませんでした。 理想に近い機能をするサンプルをみつけたました。 Three.js - exampleの WebGL_Interactive_voxelpainterを参考にして、次のように変えてみています。このサンプルとクリックによる機能自体は一緒で、さらにTrackballControlsが組み込まれたものが私が今作ろうとしているものです。 https://threejs.org/examples/?q=interactive#webgl_interactive_voxelpainter 結局またもやRaycaster動作はできずにいますが、参考ソースと比較したところ、次のようなエラーが見つかりましたが解決方法が分かりません。 エラー発生部分: voxel.position.copy( intersect.point ).add( intersect.face.normal ); エラー内容: Uncaught TypeError: Cannot read property 'point' of undefine 参考基でもPointについて宣言している部分がなく通ってしまっているのに、同じ手法で書いているにも関わらずこちらの方ではエラーを吐いている状態で混乱中です。 ※もしかしてTrackballControlsがRaycaster判定中にも優先されているのではと思い、controls.enable = false; を追加しましたが、これも変化なく・・・ ーーーーーーーーーーーーーーーーーーーー参考・修正後(Loaderの部分に少し修正を入れて、MouseEventには大幅な修正がありました。) //----------------------------------------------------- // mouse event //var isShiftDown = false; var isCtrlDown = false; var cubeGeo = new THREE.SphereGeometry( 40 ); var cubeMaterial = new THREE.MeshLambertMaterial( { color: 0xfeb74c } ); var raycaster = new THREE.Raycaster(); var mouse = new THREE.Vector2(); //document.addEventListener( 'mouseup', onDocumentMouseUp, false ); document.addEventListener( 'mousedown', onDocumentMouseDown, false ); document.addEventListener( 'keydown', onDocumentKeyDown, false ); document.addEventListener( 'keyup', onDocumentKeyUp, false ); /* function onDocumentMouseUp( event ) { event.preventDefault(); mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1; mouse.Y = - ( event.clientY / window.innerHeight ) * 2 + 1; raycaster.setFromCamera( mouse, camera ); var intersects = raycaster.intersectObjects( objects ); if ( intersects.length = 0 ) { var intersect = intersects[ 0 ]; } //render(); } */ function onDocumentMouseDown( event ){ event.preventDefault(); mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1; mouse.Y = - ( event.clientY / window.innerHeight ) * 2 + 1; raycaster.setFromCamera( mouse, camera ); var intersects = raycaster.intersectObjects( objects.children, true ); if( intersects.length > 0 ){ var intersect = intersects[ 0 ]; controls.enable = false; //delete cube if( isCtrlDown ) { if( intersect.object != plane ){ scene.remove( intersect.object ); objects.splice( objects.indexOf(intersect.object), 1 ); } } } else { controls.enable = false; var voxel = new THREE.Mesh( cubeGeo, cubeMaterial ); //voxel.position = intersect; voxel.position.copy( intersect.point ).add( intersect.face.normal ); voxel.position.divideScalar( 50 ).floor().multiplyScalar( 50 ).addScalar( 25 ); scene.add( voxel ); objects2.push( voxel ); } renderer.render( scene, camera ); } function onDocumentKeyDown( event ) { switch ( event.keyCode ) { //case 16: isShiftDown = true; break; case 17: isCtrlDown = true; break; } } function onDocumentKeyUp( event ) { switch ( event.keyCode ) { //case 16: isShiftDown = false; break; case 17: isCtrlDown = false; break; } } }, false );
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問