javascript THREE.js Ray Intersect 通过添加 div 失败
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13542175/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
THREE.js Ray Intersect fails by adding div
提问by ZedBee
My Three.js script runs fine when there is only one target div on the page (which holds renderer.domElement). As soon as I add another div with fixed height and width above the target div, ray.intersectObjects returns null. I doubt that the vector that I am creating for ray is causing the problem. Here is the code.
当页面上只有一个目标 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 );
Any ideas on how I can solve this.
关于我如何解决这个问题的任何想法。
EDIT: it is now THREE.Raycaster
(three.js r.56)
编辑:现在是THREE.Raycaster
(three.js r.56)
回答by WestLangley
The short answer is you have to take into consideration the offset
of the canvas.
简短的回答是您必须考虑offset
画布的 。
The long answer depends on how your code is written, so I'll give you two answers, which should cover the bases.
长答案取决于你的代码是如何编写的,所以我会给你两个答案,它们应该涵盖基础。
There are a lot of possible combinations, so you may have to experiment. Also, different browsers may act differently.
有很多可能的组合,因此您可能需要进行试验。此外,不同的浏览器可能会有不同的行为。
Assume your HTML is something like this:
假设你的 HTML 是这样的:
#canvas {
width: 200px;
height: 200px;
margin: 100px;
padding: 0px;
position: static; /* fixed or static */
top: 100px;
left: 100px;
}
<body>
<div id="canvas">
</body>
Your JS is something like this:
你的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 );
Method 1For the following method to work correctly, set the canvas position static; margin > 0 and padding > 0 are OK
方法一为使下面的方法正常工作,将画布位置设置为静态;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;
Method 2For this alternate method, set the canvas position fixed; set top > 0, set left > 0; padding must be 0; margin > 0 is OK
方法 2对于这种替代方法,将画布位置设置为固定;设置顶部> 0,设置左> 0;填充必须为 0;边距 > 0 是可以的
mouse.x = ( ( event.clientX - container.offsetLeft ) / container.clientWidth ) * 2 - 1;
mouse.y = - ( ( event.clientY - container.offsetTop ) / container.clientHeight ) * 2 + 1;
Here is a Fiddle if you want to experiment: http://jsfiddle.net/cn7ecoaa/
如果你想尝试,这里有一个小提琴:http: //jsfiddle.net/cn7ecoaa/
EDIT: Fiddle updated to three.js r.84
编辑:小提琴更新为three.js r.84
回答by Kris Roofe
enent.clientXis the client window offset, so to calculate the mouse position we also have to use the renderer element client window offset. Use the element.getBoundingClientRect() to get the element rect offset the window.
enent.clientX是客户端窗口偏移量,因此要计算鼠标位置,我们还必须使用渲染器元素客户端窗口偏移量。使用 element.getBoundingClientRect() 获取元素 rect 偏移窗口。
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>
回答by danivicario
WestLangley, thanks a lot for your explanation. It was really helpful as usual.
WestLangley,非常感谢您的解释。和往常一样,这真的很有帮助。
In my case, I had my chart in a div absolutely positioned, so I had to do this:
就我而言,我将图表放在绝对定位的 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;
Where rightBlock is my container, that uses only 70% of the screen.
rightBlock 是我的容器,它只使用了 70% 的屏幕。
You inspired me and help me solving this problematic issue! Thanks a lot.
您启发了我并帮助我解决了这个棘手的问题!非常感谢。