2016-12-21 12 views
0

Autodesk ForgeビューアではThree.jsで実行できる機能は実現したいが、それはできない。テストするリンクは次のとおりです。http://app.netonapp.com/JavaScript/Three.js/select_inner_objects.htmlAutodesk Forgeビューアで要素の要素をピッキングする

オブジェクト内のオブジェクトを選択する必要があります。この作業は、上のデモでTHREE.Raycasterを使用して実行できます。レイキャスターを使用して、レイが通過しているライン上のすべての要素を検出します。それから、私はオブジェクトを別のオブジェクトの背後または内側に置くことができます。

私はAutodesk Forgeビューアでこのコンセプトを試しましたが、成功しませんでした。ここでは、コードは次のようになります。

// Change this to: 
// true to use original Three.js 
// false to use Autodesk Forge Viewer API 
var useThreeJS = true; 

var container = $('div.canvas-wrap')[0]; 

container.addEventListener('mousedown', function (event) { 
    if (useThreeJS) { 
     var canvas = _viewer.impl.canvas; 
     var containerWidth = canvas.clientWidth; 
     var containerHeight = canvas.clientHeight; 

     var camera = _viewer.getCamera(); 

     var mouse = mouse || new THREE.Vector3(); 
     var raycaster = raycaster || new THREE.Raycaster(); 

     mouse.x = 2 * (event.clientX/containerWidth) - 1; 
     mouse.y = 1 - 2 * (event.clientY/containerHeight); 
     mouse.unproject(camera); 

     raycaster.set(camera.position, mouse.sub(camera.position).normalize()); 
     var intersects = raycaster.intersectObjects(objects); 

     if (intersects.length == 1) { 
      var obj = intersects[0].object; 
      obj.material.color.setRGB(1.0 - i/intersects.length, 0, 0); 
     } else if (intersects.length > 1) { 
      // Exclude the first which is the outer object (i == 0) 
      for (var i = 1; i < intersects.length; i++) { 
       var obj = intersects[i].object; 
       obj.material.color.setRGB(1.0 - i/intersects.length, 0, 0); 
      } 
     } 
    } else { 
     var vp = _viewer.impl.clientToViewport(event.canvasX, event.canvasY); 
     var renderer = _viewer.impl.renderer(); 

     var dbId = renderer.idAtPixel(vp.x, vp.y); 
     if (dbId) { 
      console.debug("Selected Id: " + dbId); 
      _viewer.select(dbId); 
      _viewer.impl.invalidate(true); 
     } 
    } 
}, false); 

私はフォージの視聴者がピッキングピクセルにある要素を取得するために素晴らしいですviewer.impl.renderer().idAtPixel方法を持っていました。しかし、ピッキングピクセルで(アンダーまたはネストされている)すべての要素を選択するために、もっとやりたいと思っています。 Forge Viewer APIを使ってどうすればいいですか?

答えて

1

別のpostのZhong Wuの提案に基づいて、ここでは別の要素の下または内側にある要素を選択するための最終的な解決策があります。 Autodesk Forgeビューアの拡張機能を使用して簡単に使用できました。

/////////////////////////////////////////////////////////////////////////////// 
 
// InnerSelection viewer extension 
 
// by Khoa Ho, December 2016 
 
// 
 
/////////////////////////////////////////////////////////////////////////////// 
 
AutodeskNamespace("Autodesk.ADN.Viewing.Extension"); 
 

 
Autodesk.ADN.Viewing.Extension.InnerSelection = function (viewer, options) { 
 

 
    Autodesk.Viewing.Extension.call(this, viewer, options); 
 

 
    var _self = this; 
 

 
    var _container = viewer.canvas.parentElement; 
 
    var _renderer = viewer.impl.renderer(); 
 
    var _instanceTree = viewer.model.getData().instanceTree; 
 
    var _fragmentList = viewer.model.getFragmentList(); 
 
    var _eventSelectionChanged = false; 
 
    var _viewport; 
 
    var _outerDbId; 
 

 
    _self.load = function() { 
 

 
     _container.addEventListener('mousedown', 
 
      onMouseDown); 
 

 
     viewer.addEventListener(
 
      Autodesk.Viewing.SELECTION_CHANGED_EVENT, 
 
      onItemSelected); 
 

 
     console.log('Autodesk.ADN.Viewing.Extension.InnerSelection loaded'); 
 

 
     return true; 
 
    }; 
 

 
    _self.unload = function() { 
 

 
     _container.removeEventListener('mousedown', 
 
      onMouseDown); 
 

 
     viewer.removeEventListener(
 
      Autodesk.Viewing.SELECTION_CHANGED_EVENT, 
 
      onItemSelected); 
 

 
     console.log('Autodesk.ADN.Viewing.Extension.InnerSelection unloaded'); 
 

 
     return true; 
 
    }; 
 

 
    function onMouseDown(e) { 
 

 
     var viewport = viewer.impl.clientToViewport(e.canvasX, e.canvasY); 
 
     _viewport = viewport; // Keep this viewport to use in onItemSelected() 
 

 
     var dbId = _renderer.idAtPixel(viewport.x, viewport.y); 
 

 
     if (_outerDbId == dbId) { 
 
      _outerDbId = -1; 
 

 
      // Deselect everything 
 
      viewer.select(); 
 
     } else { 
 
      _outerDbId = dbId; 
 

 
      // Hide outer element temporarily to allow picking its behind element 
 
      viewer.hideById(dbId); 
 

 
      _eventSelectionChanged = true; 
 
     } 
 

 
     viewer.impl.sceneUpdated(true); 
 
    } 
 

 
    function onItemSelected(e) { 
 

 
     if (_eventSelectionChanged) { 
 

 
      // Prevent self looping on selection 
 
      _eventSelectionChanged = false; 
 

 
      // Show outer element back 
 
      viewer.show(_outerDbId); 
 

 
      // Get inner element Id after the outer element 
 
      // was just hidden on mouse down event 
 
      var innerDbId = _renderer.idAtPixel(_viewport.x, _viewport.y); 
 

 
      if (innerDbId > -1) { 
 
       // Select the inner element when it is found 
 
       viewer.select(innerDbId); 
 

 
       console.debug("Selected inner Id: " + innerDbId); 
 

 
      } else if (_outerDbId > -1) { 
 
       // Select the outer element if the inner element is not found 
 
       viewer.select(_outerDbId); 
 

 
       console.debug("Selected outer Id: " + _outerDbId); 
 

 
      } 
 
     } 
 
    } 
 

 
}; 
 

 
Autodesk.ADN.Viewing.Extension.InnerSelection.prototype = 
 
    Object.create(Autodesk.Viewing.Extension.prototype); 
 

 
Autodesk.ADN.Viewing.Extension.InnerSelection.prototype.constructor = 
 
    Autodesk.ADN.Viewing.Extension.InnerSelection; 
 

 
Autodesk.Viewing.theExtensionManager.registerExtension(
 
    'Autodesk.ADN.Viewing.Extension.InnerSelection', 
 
    Autodesk.ADN.Viewing.Extension.InnerSelection);

0

現在のところ、マウスクリックで選択すると、ビューアは透明な要素を無視しないので、透明であっても要素を選択します。以下は、私がカーソルの下にあるものを追跡するために使用したコードです。多分役に立つかもしれません。

// use jQuery to bind a mouve move event 
$(_viewer.container).bind("mousemove", onMouseMove); 

function onMouseMove(e) { 
    var screenPoint = { 
     x: event.clientX, 
     y: event.clientY 
    }; 
    var n = normalize(screenPoint); 
    var dbId = /*_viewer.utilities.getHitPoint*/ getHitDbId(n.x, n.y); 
    // 
    // use the dbId somehow... 
    // 
} 

// This is a built-in method getHitPoint, but the original returns 
// the hit point, so this modified version returns the dbId 
function getHitDbId(){ 
    y = 1.0 - y; 
    x = x * 2.0 - 1.0; 
    y = y * 2.0 - 1.0; 
    var vpVec = new THREE.Vector3(x, y, 1); 
    var result = _viewer.impl.hitTestViewport(vpVec, false); 

    //return result ? result.intersectPoint : null; // original implementation 
    return result ? result.dbId : null; 
} 

function normalize(screenPoint) { 
    var viewport = _viewer.navigation.getScreenViewport(); 
    var n = { 
     x: (screenPoint.x - viewport.left)/viewport.width, 
     y: (screenPoint.y - viewport.top)/viewport.height 
    }; 
    return n; 
} 
+0

'viewer.impl.hitTestViewport'は隠された/ゴースト要素の背後にある要素を選択することはできません。 'viewer.impl.renderer()。idAtPixel'がうまく機能します。 –

0

私はマウスピックで要素を選択するviewer.impl.hitTestViewportより良い作品viewer.impl.renderer().idAtPixel方法を参照してください。最初の要素はhidden/ghost要素をクリックすることで要素のobjectIdを取得できます。一方、第二はできません。ここではテストにコードがある:

var container = $('div.canvas-wrap')[0]; 

container.addEventListener('mousedown', function (event) { 

    var clickThroughHiddenElement = true; 

    if (clickThroughHiddenElement) { 
     var vp = _viewer.impl.clientToViewport(event.canvasX, event.canvasY); 
     var renderer = _viewer.impl.renderer(); 

     var dbId = renderer.idAtPixel(vp.x, vp.y); 
     if (!!dbId) { 
      _viewer.select(dbId); 
     } 
     console.debug("Selected Id: " + dbId); 
    } else { 
     var screenPoint = { 
      x: event.clientX, 
      y: event.clientY 
     }; 
     var viewport = _viewer.navigation.getScreenViewport(); 
     var x = (screenPoint.x - viewport.left)/viewport.width; 
     var y = (screenPoint.y - viewport.top)/viewport.height; 
     // Normalize point 
     x = x * 2.0 - 1.0; 
     y = (1.0 - y) * 2.0 - 1.0; 

     var vpVec = new THREE.Vector3(x, y, 1); 
     var result = _viewer.impl.hitTestViewport(vpVec, false); 
     if (!!result) { 
      var dbId = result.dbId; 
      _viewer.select(dbId); 
      console.debug("Selected Id: " + dbId); 
     } 
    } 
} 

しかし、彼らは背後にある要素を取得するために、透明要素を順にクリックして、私が欲しいものではありません。ユーザーが透明な要素を選択すると、それが選択されます。ユーザーが内部要素を選択した場合、ピッキング内部要素を選択するために外側透明要素は無視されます。

私は、マウスのクリックで交差を検出するために、要素の境界ボックスを持つTHREE.Raycasterを使用します。私の問題は、私のThree.js demoのように、Forgeビューアでやり遂げることができるようです。

関連する問題