threejs 射线拾取 物体注册点击事件

threejs 基本使用

  • 创建场景
  • 创建相机
  • 创建几何体
  • 给几何体注册点击事件

代码如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>模板代码</title>
    <style>
        canvas{
            display: block;
        }
        body {
            margin: 0;
            overscroll-behavior: none;
        }
        #btns{
            position: absolute;
            top:10%;
            width: 500px;
            height: 100px;
            left: 50%;
            transform:translateX(-50%);
        }
    </style>
</head>
<body>
<div id="btns"></div>

<!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported -->
<script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>

<script type="importmap">
			{
				"imports": {
					"three": "./three.js-master/build/three.module.js"
				}
			}
		</script>
<script type="module">
    import * as THREE from './three.js-master/build/three.module.js';
    import {OrbitControls} from "./three.js-master/examples/jsm/controls/OrbitControls.js";
    // import anime from "./js/anime.es.js"; // 暂时没有用

    //创建一个做拾取的数组
    let selectArray = [];

    let scene,renderer,camera,orbitControls;
    function init(){
        scene = new THREE.Scene(); // 创建一个场景
        renderer = new THREE.WebGLRenderer({
            alpha:true, // 透明
            antialias:true // 抗锯齿开启
        });
        renderer.setSize(window.innerWidth,window.innerHeight); // 设置渲染器的宽高
        document.body.appendChild(renderer.domElement);
        /** 
         * three.js里有几种不同的相机,在这里,我们使用的是PerspectiveCamera(透视摄像机)。
第一个参数是视野角度(FOV)。视野角度就是无论在什么时候,你所能在显示器上看到的场景的范围,它的单位是角度(与弧度区分开)。
第二个参数是长宽比(aspect ratio)。 也就是你用一个物体的宽除以它的高的值。比如说,当你在一个宽屏电视上播放老电影时,可以看到图像仿佛是被压扁的。
接下来的两个参数是近截面(near)和远截面(far)。 当物体某些部分比摄像机的远截面远或者比近截面近的时候,该这些部分将不会被渲染到场景中。或许现在你不用担心这个值的影响,但未来为了获得更好的渲染性能,你将可以在你的应用程序里去设置它。
        */
        camera = new THREE.PerspectiveCamera(60,window.innerWidth/window.innerHeight,0.01,50000); // 创建相机并设置 
        camera.position.set(10,10,10); // 设置相机的位置
        orbitControls = new OrbitControls(camera,renderer.domElement); // 一个是控制的相机对象 第二个是检测事件的dom 元素
        camera.add(new THREE.PointLight()); // 创建一个点光源 点光源(PointLight)表示的是从一个点朝各个方向发射出光线的一种光照效果
        scene.add(camera); // 相机添加到场景中
        let helper = new THREE.GridHelper(50,50);
        scene.add(helper);

    }
    function addMesh(){

        //创建一个长宽高为1的盒子
        let geometry = new THREE.BoxGeometry(1,1,1);

        //以盒子几何体创建100个颜色不同的盒子Mesh
        for(let i = 0;i< 100;i++){
            let material = new THREE.MeshBasicMaterial({
                color:0xffffff * Math.random()
            });
            let mesh = new THREE.Mesh(geometry,material);
            mesh.position.x = Math.random() * 50 - 25; //x轴偏移 -25 ~ 25
            mesh.position.y = 0.5; //y轴高度上升0.5,盒子的高度为1,这样可以直接放置到地面上
            mesh.position.z = Math.random() * 50 - 25;
            selectArray.push(mesh);
            scene.add(mesh);
        }

        //创建射线对象
        let raycaster = new THREE.Raycaster();
        //创建用于保存鼠标点击位置的二维向量
        let mousePoint = new THREE.Vector2();


        renderer.domElement.addEventListener('click',(e)=>{
            let x = e.clientX;
            let y = e.clientY;

            mousePoint.x =  ( x / window.innerWidth  ) * 2 - 1;
            mousePoint.y = -( y / window.innerHeight ) * 2 + 1;

            /* 算法公式:
               鼠标点击位置x/页面宽度 = x轴比例
               x轴比例 * 2 -1 = 坐标系扩大两倍,且坐标系x轴0点向右移动100%
               y轴计算要麻烦一点,html的y轴从左上角开始计算,所以我们先计算比例,然后扩大坐标系
               然后再将当前坐标系*-1,可以让坐标系反向,原先y轴的正方向变成了由屏幕下方到屏幕上方
               坐标系转负后,这里还需要加一个1来让坐标系放到屏幕中心
               最终得到的结果是,在以屏幕正中心为坐标系原点的,x,y位置
            */

            //将射线绑定到相机上,并通过mousePoint定位到相机的指定位置
            raycaster.setFromCamera(mousePoint,camera);

            //拾取物体
            let intersects = raycaster.intersectObjects(selectArray);
            console.log(intersects);
            if(intersects.length > 0){
                let intersect = intersects[0];
                console.log(intersect);
                let object = intersect.object;
                object.material.color = new THREE.Color("#ff0000");
            }
        });
        
        /** 
         * 给物体注册点击事件
        */
        renderer.domElement.addEventListener('mousemove',(e)=>{
            let x = e.clientX;
            let y = e.clientY;
            let rx =  ( x / window.innerWidth  ) * 2 - 1;
            let ry = -( y / window.innerHeight ) * 2 + 1;
            console.log(rx,ry)
        })

    }
    function render(){
        renderer.render(scene,camera);
        requestAnimationFrame(render);
    }
    init();
    addMesh();
    render();
</script>
</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值