###前提・実現したいこと
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>
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。