Autodesk forge 在Autodesk Forge viewer中图元的图元下拾取

Autodesk forge 在Autodesk Forge viewer中图元的图元下拾取,autodesk-forge,autodesk-viewer,Autodesk Forge,Autodesk Viewer,我想实现一个功能,我可以在Three.js中实现,但在Autodesk Forge viewer中无法实现。以下是测试的链接: 要求是选择对象内部的对象。在上面的演示中,这项工作可以使用三个.Raycaster来完成,即使用Raycaster来检测光线通过的线路上的所有元素。然后我可以在另一个对象后面或内部获取对象 我在Autodesk Forge viewer中尝试了此概念,但没有成功。代码如下: // Change this to: // true to use original Three

我想实现一个功能,我可以在Three.js中实现,但在Autodesk Forge viewer中无法实现。以下是测试的链接:

要求是选择对象内部的对象。在上面的演示中,这项工作可以使用三个.Raycaster来完成,即使用Raycaster来检测光线通过的线路上的所有元素。然后我可以在另一个对象后面或内部获取对象

我在Autodesk Forge viewer中尝试了此概念,但没有成功。代码如下:

// 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);
//将此更改为:
//使用original Three.js时为true
//false以使用Autodesk Forge Viewer API
var usetreejs=true;
var container=$('div.canvas-wrap')[0];
container.addEventListener('mousedown',函数(事件){
if(usetreejs){
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 | |新三个。raycaster();
mouse.x=2*(event.clientX/containerWidth)-1;
mouse.y=1-2*(event.clientY/containerHeight);
鼠标。取消投影(相机);
raycaster.set(camera.position,mouse.sub(camera.position.normalize());
var intersects=raycaster.intersectObjects(对象);
如果(相交长度==1){
var obj=相交[0]。对象;
对象材质颜色设置RGB(1.0-i/相交长度,0,0);
}否则如果(相交长度>1){
//排除第一个外部对象(i==0)
对于(变量i=1;i
我发现Forge viewer具有
viewer.impl.renderer().idAtPixel
方法,该方法非常适合在拾取像素处获取元素。但是,我希望它能做更多的工作,在拾取像素处选择所有元素(在下或嵌套)。如何使用Forge Viewer API实现这一点?

从现在起(2016年12月),当您使用鼠标单击进行选择时,查看器将不会忽略透明元素,因此它将选择一个即使透明的元素。下面是我用来跟踪光标下的内容的代码,可能有用

// 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;
}

我看到方法
viewer.impl.renderer().idAtPixel
viewer.impl.hitTestViewport
更适合在鼠标拾取时选择元素。第一个可以通过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);
        }
    }
}
然而,它们不是我想要的,通过单击透明元素来获取后面的元素。如果用户选择透明元素,则将选中它。如果用户选择内部元素,它将忽略外部透明元素以选择拾取内部元素


我检查Forge viewer使用3.Raycaster和元素边界框来检测鼠标点击的交点。似乎我的问题在Forge viewer中是可以解决的,就像在我的Three.js中一样。

根据另一个元素中钟武的建议,这里是选择另一个元素下面或里面的元素的最终解决方案。我创建了Autodesk Forge viewer扩展以方便使用

///////////////////////////////////////////////////////////////////////////////
//内部选择查看器扩展
//Khoa Ho,2016年12月
//
///////////////////////////////////////////////////////////////////////////////
AutodeskNamespace(“Autodesk.ADN.Viewing.Extension”);
Autodesk.ADN.Viewing.Extension.InnerSelection=函数(查看器,选项){
Autodesk.Viewing.Extension.call(此、查看器、选项);
var _self=这个;
var\u container=viewer.canvas.parentElement;
var_renderer=viewer.impl.renderer();
var_instanceTree=viewer.model.getData().instanceTree;
var_fragmentList=viewer.model.getFragmentList();
var\u eventSelectionChanged=false;
var_视区;
var_外部出价;
_self.load=函数(){
_container.addEventListener('mousedown',
(下载),;
viewer.addEventListener(
Autodesk.Viewing.SELECTION\u已更改\u事件,
(已选定);
console.log('Autodesk.ADN.Viewing.Extension.InnerSelection loaded');
返回true;
};
_self.unload=函数(){
_container.removeEventListener('mousedown',
(下载),;
viewer.removeEventListener(
Autodesk.Viewing.SELECTION\u已更改\u事件,
(已选定);
console.log('Autodesk.ADN.Viewing.Extension.InnerSelection');
返回true;
};
函数onMouseDown(e){
var viewport=viewer.impl.clientToViewport(e.canvasX,e.canvasY);
_viewport=viewport;//保留此视口以在onItemSelected()中使用
var dbId=_renderer.idAtPixel(viewport.x,viewport.y);
if(_outerDbId==dbId){
_outerDbId=-1;
//取消选择所有内容
viewer.select();
}否则{
_outerDbId=dbId;
//暂时隐藏外部图元以允许拾取其后面的图元
viewer.hideById(dbId);
_eventSelectionChanged=true;
}
viewer.impl.sceneUpdated(真);
}
已选择功能(e){
如果(\u事件选择已更改){
//防止选择上的自循环
_eventSelectionChanged=false;
//向后显示外部元素