three.js中的事件
阿新 • • 發佈:2020-01-16
以上一篇入門篇為例來簡單的設定下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>