【问题标题】:THREE.js Ray Intersect fails by adding divTHREE.js Ray Intersect 通过添加 div 失败
【发布时间】:2012-11-12 14:11:40
【问题描述】:

当页面上只有一个目标 div(包含 renderer.domElement)时,我的 Three.js 脚本运行良好。一旦我在目标 div 上方添加另一个具有固定高度和宽度的 div,ray.intersectObjects 就会返回 null。我怀疑我为 ray 创建的向量是否会导致问题。这是代码。

var vector = new THREE.Vector3( ( event.clientX / divWidth ) * 2 - 1, -( event.clientY / divHeight ) * 2 + 1, 0.5 );

projector.unprojectVector( vector, camera );

var ray = new THREE.Ray( camera.position, vector.subSelf( camera.position ).normalize() );

var intersects = ray.intersectObjects( myObjects, true );

关于如何解决这个问题的任何想法。

编辑:现在是 THREE.Raycaster (three.js r.56)

【问题讨论】:

    标签: javascript html three.js


    【解决方案1】:

    简短的回答是你必须考虑到画布的offset

    长答案取决于你的代码是如何编写的,所以我会给你两个答案,应该涵盖基础。

    有很多可能的组合,因此您可能需要进行试验。此外,不同的浏览器可能会有不同的行为。

    假设你的 HTML 是这样的:

    #canvas {
        width: 200px;
        height: 200px;
        margin: 100px;
        padding: 0px;
        position: static; /* fixed or static */
        top: 100px;
        left: 100px;
    }
    
    <body>
        <div id="canvas">
    </body>
    

    你的 JS 是这样的:

    var CANVAS_WIDTH = 200,
    CANVAS_HEIGHT = 200;
    
    var container = document.getElementById( 'canvas' );
    document.body.appendChild( container );
    
    renderer = new THREE.WebGLRenderer();
    renderer.setSize( CANVAS_WIDTH, CANVAS_HEIGHT );
    container.appendChild( renderer.domElement );
    

    方法一为了让下面的方法正常工作,设置画布位置static; margin > 0 和 padding > 0 都可以

    mouse.x = ( ( event.clientX - renderer.domElement.offsetLeft ) / renderer.domElement.clientWidth ) * 2 - 1;
    mouse.y = - ( ( event.clientY - renderer.domElement.offsetTop ) / renderer.domElement.clientHeight ) * 2 + 1;
    

    方法二对于这个替代方法,设置画布位置固定;置顶 > 0,置左 > 0;填充必须为 0;边距 > 0 即可

    mouse.x = ( ( event.clientX - container.offsetLeft ) / container.clientWidth ) * 2 - 1;
    mouse.y = - ( ( event.clientY - container.offsetTop ) / container.clientHeight ) * 2 + 1;
    

    如果您想进行实验,这里有一个 Fiddle:http://jsfiddle.net/cn7ecoaa/

    编辑:小提琴更新为 three.js r.84

    【讨论】:

    • 对于不等于 1 的设备(视网膜显示器等),您可能需要将鼠标 x 和 y 计算中的分子乘以 renderer.devicePixelRatio。
    【解决方案2】:

    enent.clientX 是客户端窗口偏移量,因此要计算鼠标位置,我们还必须使用渲染器元素客户端窗口偏移量。 使用 element.getBoundingClientRect() 获取元素矩形偏移窗口。

    var rect = renderer.domElement.getBoundingClientRect();
    mouse.x = ( ( event.clientX - rect.left ) / ( rect.width - rect.left ) ) * 2 - 1;
    mouse.y = - ( ( event.clientY - rect.top ) / ( rect.bottom - rect.top) ) * 2 + 1;
    

    <html>
    <head>
    <script src="http://threejs.org/build/three.min.js"></script>
    
        <link rel="stylesheet" href="http://libs.baidu.com/bootstrap/3.0.3/css/bootstrap.min.css" />
    
    
    <style>
    body {
        font-family: Monospace;
        background-color: #fff;
        margin: 0px;
        overflow: hidden;
    }
    
    #canvas {
        background-color: #000;
        width: 200px;
        height: 200px;
        border: 1px solid black;
        margin: 10px;
        padding: 0px;
        top: 10px;
        left: 100px;
    }
    
    .border {
        padding:10px; 
        margin:10px;
    }
    
    </style>
    </head>
    <body>
    <div class="border">
    	<div class="border">
    		<div id="canvas"></div>
    	</div>
    </div>
    <script>
    // Three.js ray.intersects with offset canvas
    
    var container, camera, scene, renderer, mesh,
    
        objects = [],
        
        count = 0,
    
        CANVAS_WIDTH = 200,
        CANVAS_HEIGHT = 200;
    
    // info
    info = document.createElement( 'div' );
    info.style.position = 'absolute';
    info.style.top = '30px';
    info.style.width = '100%';
    info.style.textAlign = 'center';
    info.style.color = '#f00';
    info.style.backgroundColor = 'transparent';
    info.style.zIndex = '1';
    info.style.fontFamily = 'Monospace';
    info.innerHTML = 'INTERSECT Count: ' + count;
    info.style.userSelect = "none";
    info.style.webkitUserSelect = "none";
    info.style.MozUserSelect = "none";
    document.body.appendChild( info );
    
    container = document.getElementById( 'canvas' );
    
    renderer = new THREE.WebGLRenderer();
    renderer.setSize( CANVAS_WIDTH, CANVAS_HEIGHT );
    container.appendChild( renderer.domElement );
    
    scene = new THREE.Scene();
    
    camera = new THREE.PerspectiveCamera( 45, CANVAS_WIDTH / CANVAS_HEIGHT, 1, 1000 );
    camera.position.y = 250;
    camera.position.z = 500;
    camera.lookAt( scene.position );
    scene.add( camera );
    
    scene.add( new THREE.AmbientLight( 0x222222 ) );
    
    var light = new THREE.PointLight( 0xffffff, 1 );
    camera.add( light );
    
    mesh = new THREE.Mesh( 
    	new THREE.BoxGeometry( 200, 200, 200, 1, 1, 1 ), 
    	new THREE.MeshPhongMaterial( { color : 0x0080ff } 
    ) );
    scene.add( mesh );
    objects.push( mesh );
    
    // find intersections
    var raycaster = new THREE.Raycaster();
    var mouse = new THREE.Vector2();
    
    // mouse listener
    document.addEventListener( 'mousedown', function( event ) {
        
     var rect = renderer.domElement.getBoundingClientRect();
    mouse.x = ( ( event.clientX - rect.left ) / ( rect.width - rect.left ) ) * 2 - 1;
    mouse.y = - ( ( event.clientY - rect.top ) / ( rect.bottom - rect.top) ) * 2 + 1;
      
    	raycaster.setFromCamera( mouse, camera );
    
        intersects = raycaster.intersectObjects( objects );
    
        if ( intersects.length > 0 ) {
            
            info.innerHTML = 'INTERSECT Count: ' + ++count;
            
        }
    
    }, false );
    
    function render() {
    
        mesh.rotation.y += 0.01;
        
        renderer.render( scene, camera );
    
    }
    
    (function animate() {
    
        requestAnimationFrame( animate );
    
        render();
    
    })();
    
    </script>
    </body>
    </html>

    【讨论】:

    • 我通过修改mouse.x分母mouse.x = ( ( event.clientX - rect.left ) / ( rect.right - rect.left ) ) * 2 - 1;得到了不错的结果
    • @beepscore 您的评论是正确的,对我帮助很大,谢谢
    【解决方案3】:

    WestLangley,非常感谢您的解释。像往常一样真的很有帮助。

    在我的例子中,我的图表在一个绝对定位的 div 中,所以我必须这样做:

        var offset = $('.rightBlock').offset();
    
    
        mouse.x = ( ( event.clientX - offset.left ) / renderer.domElement.width ) * 2 - 1;
        mouse.y = - ( ( event.clientY - offset.top ) / renderer.domElement.height ) * 2 + 1;
    

    rightBlock 是我的容器,它只使用了 70% 的屏幕。

    您启发了我并帮助我解决了这个问题!非常感谢。

    【讨论】:

    • 好吧,这在你缩小几何时不起作用,会有偏移,你知道如何解决这个问题吗?
    猜你喜欢
    • 1970-01-01
    • 2010-12-17
    • 2011-05-19
    • 1970-01-01
    • 1970-01-01
    • 2013-07-28
    • 2020-03-13
    • 2017-08-10
    • 2016-05-20
    相关资源
    最近更新 更多