以上一篇入門篇為例來簡單的設置下3d模型當中的交互事件,上一篇我們已經完成了在3d頁面中添加了一個紅色球,下面我們給這個球一個點擊事件讓它Y軸位置上升,再設置一個鼠標移入到球上時讓其變色。
1.其實three.js當中沒有事件可以直接選中物體的,我們需要監聽window對象來完成與3d頁面的交互,通過使用到three.js當中RayCaster對象,用於在三維空間中進行鼠標拾取,原理是:相機與鼠標所在的設備坐標之間的連線與哪些物體相交。相交的物體離屏幕越近的越靠前,所以第一個物體就是我們選中的對象。
第一步:給window對象添加點擊事件監聽器;
window.addEventListener('mousedown', mouseDownFuc);
第二步:在事件監聽函數里拾取到點擊的對象集合;
function mouseDownFuc(){
let raycaster = new THREE.Raycaster();//創建光線投射對象
let mouse = new THREE.Vector2();//創建二維平面
let intersectsObjArr = getSelsectOBj(mouse,raycaster, e);//通過封裝的getSelsectOBj函數獲取鼠標選中對象集合,e是點擊事件對象
}
//獲取事件操作對象
function getSelsectOBj(mouse,raycaster, e) {
//將html坐標系轉化為webgl坐標系,並確定鼠標點擊位置
mouse.x = e.clientX / renderer.domElement.clientWidth*2-1;
mouse.y = -(e.clientY / renderer.domElement.clientHeight*2)+1;
raycaster.setFromCamera(mouse,camera);//以camera為z坐標,確定所點擊物體的3D空間位置
let intersects = raycaster.intersectObjects(scene.children, true);//確定所點擊位置上的物體數量集合
return intersects;//返回連線經過的物體集合
}
第三步:判斷intersectsObjArr集合長度不為零,確認我們鼠標點擊的地方有物體,如果有物體那么intersectsObjArr[0]就是我們選中的對象,通過頁面console.log(intersectsObjArr[0])發現intersectsObjArr[0]包含了相交點的許多信息,而我們只需要交點的對象,所以我們需要取到intersectsObjArr[0].object對象;然后我們還需要進行一次判斷當前對象就是我們點擊的對象,在這里我們還得回到創建物體時給它的name屬性一個值進行區分物體。最后給它position屬性值的Y軸坐標設為50;
myBall.name = 'redBall';//創建物體時給它name屬性一個名稱
if(intersectsObjArr.length > 0){
if(intersectsObjArr[0].object.name == 'redBall'){
intersectsObjArr[0].object.position.y = 50;
}
}
以上就是我們完成了3d頁面物體點擊事件,然后就是鼠標的移入到物體變色,移出時顏色還原,這和2d頁面的移入移出不太一樣,因為我們是給window對象加的監聽器,然后通過RayCaster對象來拾取到物體的,所以我們這里需要給window對象加鼠標移動事件來判斷鼠標是否移動我們的物體上。其步驟同上點擊事件一樣。
window.addEventListener('mousemove', mouseMoveFuc);
function mouseMoveFuc(){
let raycaster = new THREE.Raycaster();//創建光線投射對象
let mouse = new THREE.Vector2();//創建二維平面
let intersectsObjArr = getSelsectOBj(mouse,raycaster, e);//通過封裝的getSelsectOBj函數獲取鼠標選中對象集合,e是點擊事件對象
if(intersectsObjArr.length > 0){
if(intersectsObjArr[0].object.name == 'redBall'){
intersectsObjArr[0].object.material = new THREE.MeshPhongMaterial( { color: 'orange'});//移到物體上時顏色變成橘色
document.getElementsByTagName('body')[0].style.cursor = 'pointer';//移到物體上時鼠標顯示為手
}
}else{
myBall.material = new THREE.MeshPhongMaterial( { color: 0xff0000});//移出物體時顏色變成原來的紅色
document.getElementsByTagName('body')[0].style.cursor = 'default';//移出物體時鼠標顯示為默認
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<title>event</title>
<style>
body {
margin: 0;
padding: 0;
height: 100vh;
width: 100vw;
overflow: hidden;
background: url('img/bgImg.jpg') no-repeat fixed;
background-size: 100% 100%;
}
</style>
</head>
<body>
<script src="lib/three.min.js"></script>
<script src="lib/OrbitControls.js"></script>
<script>
window.onload = function(){
let scene,camera,renderer,myBall;
initThreeScene();
//物體的事件交互
window.addEventListener('mousedown', mouseDownFuc);
window.addEventListener('mousemove', mouseMoveFuc);
function mouseDownFuc (e) {
let raycaster = new THREE.Raycaster();//光線投射,用於確定鼠標點擊位置
let mouse = new THREE.Vector2();//創建二維平面
let intersects = getSelsectOBj(mouse,raycaster, e);
if(intersects.length > 0) {
console.log(intersects[0])
if(intersects[0].object.name == 'myBall') {
myBall.position.y = 50;
}
}
}
function mouseMoveFuc (e) {
let raycaster = new THREE.Raycaster();//光線投射,用於確定鼠標點擊位置
let mouse = new THREE.Vector2();//創建二維平面
let intersects = getSelsectOBj(mouse,raycaster, e);
if(intersects.length > 0) {
if(intersects[0].object.name == 'myBall') {
myBall.material = new THREE.MeshPhongMaterial( { color: 'orange'});
document.getElementsByTagName('body')[0].style.cursor = 'pointer';
}
}else {
myBall.material = new THREE.MeshPhongMaterial( { color: 0xff0000});
document.getElementsByTagName('body')[0].style.cursor = 'default';
}
}
//獲取事件操作對象
function getSelsectOBj(mouse,raycaster, e) {
//將html坐標系轉化為webgl坐標系,並確定鼠標點擊位置
mouse.x = e.clientX / renderer.domElement.clientWidth*2-1;
mouse.y = -(e.clientY / renderer.domElement.clientHeight*2)+1;
//以camera為z坐標,確定所點擊物體的3D空間位置
raycaster.setFromCamera(mouse,camera);
//確定所點擊位置上的物體數量
let intersects = raycaster.intersectObjects(scene.children, true);
return intersects;
}
function initThreeScene() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.1, 2000 );
camera.position.set( 0, 50,300 );
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });//antialias: true;讓渲染的平面是光滑的,alpha: true;讓渲染的3d背景透明。
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild(renderer.domElement );
// 給場景添加一個環境光
let ambientLight = new THREE.AmbientLight( 0xf5f5f5);
scene.add( ambientLight );
//輔助線
let grid = new THREE.GridHelper( 400, 30, 0xcccccc, 0xcccccc );
scene.add( grid );
//創建的球
let ball = new THREE.SphereGeometry( 25, 100, 100 );//25:球半徑 第一個100:水平分割面的數量. 第二個100:垂直分割面的數量.
let ballColor = new THREE.MeshPhongMaterial( { color: 0xff0000 } );
myBall = new THREE.Mesh( ball , ballColor );
myBall.name = 'myBall';
scene.add( myBall );
let controls =new THREE.OrbitControls(camera, renderer.domElement);
controls.enableZoom =true;//允許縮放
//設置相機移動距離
controls.minDistance = 1;
controls.maxDistance = 2000;
controls.enableRotate =true;
function render() {
requestAnimationFrame( render );
renderer.render( scene, camera );
}
render();
window.onresize = function () {
camera.aspect = window.innerWidth / window.innerHeight;//相機重置可視范圍
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );//渲染器重新渲染可視范圍
}
}
}
</script>
</body>
</html>