Three.js中光线投射Raycaster的简单使用案例 与模型的交互,当鼠标移动到模型时出现信息框

2023-11-19

 无用的话:本人是编程小白,想创建一个氛围好的技术交流群,喜欢技术分享、技术指导、技术交流的朋友可以进Q群 732515998 大家一起快乐编程

想发公告的就不要进来了


目录

说明 

 创建两个模型

基础代码 

基础代码效果图如下:

重点!!! 

 创建光线投射Raycaster实例步骤

1.准备一个盒子,用来展示模型的长宽高信息,初始化时先隐藏该盒子

2.创建光线投射Raycaster实例

        1.创建 Raycaster 实例 

          2.为窗口绑定事件 pointermove 想使用点击事件 click 的可以自行修改

        3.定义窗口触发 pointermove 事件所执行的回调函数 onPointerMove 

        4.通过摄像机和鼠标位置更新射线

完整代码如下:

效果图如下 :

 结尾


说明 

说明:该案例是基于Vue2创建,如果未使用Ve2请自行修改代码,另外由于使用的是已经下载的Three.js,所以运行前请确保已安装Three.js以方便引入,未安装可以使用 npm install three 进行安装

 创建两个模型

先创建两个基本模型为 光线投射Raycaster 做铺垫

下面是一个名为 model 组件的编写,读者可以自行挂载在Vue示例上  

另外如果有 model 命名带来的错误,可以在文件 vue.config.js 中添加配置 lintOnSave: false

基础代码 

<template>
    <div ref="container">
        
    </div>
</template>

<script>
import * as THREE from "three";
import {OrbitControls} from "three/addons/controls/OrbitControls.js";

export default {
    name: "model",
    data() {
        return {
            //场景
            scene: null,
            //摄影机
            camera: null,
            //渲染器
            renderer: null,
            //相机控件
            controls: null,
        }
    },
    mounted() {
        // 调用方法创建场景、相机、渲染器和相机控件
        this.createScene();
        this.createCamera();
        this.createRenderer();
        this.createControls();

        // 创建两个不同大小的立方体模型,材质使用不受光照影响的 MeshBasicMaterial 材质
        const cube1 = new THREE.Mesh(
            new THREE.BoxGeometry(3, 2, 1),
            new THREE.MeshBasicMaterial({color: 0xff0000})
        );
        const cube2 = new THREE.Mesh(
            new THREE.BoxGeometry(1, 2, 3),
            new THREE.MeshBasicMaterial({color: 0x00ff00})
        );
        cube1.position.set(-2, 0, 0);
        cube2.position.set(2, 0, 0);
        this.scene.add(cube1, cube2);

        const render = () => {
            //手动更改相机的变换后,必须调用controls.update()
            this.controls.update()
            this.renderer.render(this.scene, this.camera);
            requestAnimationFrame(render);
        };
        render();
    },
    methods: {
        //创建场景
        createScene() {
            this.scene = new THREE.Scene();
        },
        //创建相机
        createCamera() {
            this.camera = new THREE.PerspectiveCamera(
                45,
                window.innerWidth / window.innerHeight,
                1,
                1000
            );
            this.camera.position.set(0, 0, 5);
        },
        //创建渲染器
        createRenderer() {
            this.renderer = new THREE.WebGLRenderer({antialias: true}); //antialias:是否执行抗锯齿,默认为false.
            this.renderer.setSize(window.innerWidth, window.innerHeight);
            this.$refs.container.appendChild(this.renderer.domElement);
        },
        //创建相机控件
        createControls() {
            this.controls = new OrbitControls(this.camera, this.renderer.domElement);
        }
    }
};
</script>

<style scoped>

</style>

基础代码效果图如下:


重点!!! 

 创建光线投射Raycaster实例步骤

1.准备一个盒子,用来展示模型的长宽高信息,初始化时先隐藏该盒子

template>
    <div ref="container">
        <div id="infoBox"></div>
    </div>
</template>

//盒子样式如下: (要是觉得盒子丑大家可以自己修改,哈哈)
#infoBox{
    display: none;
    position: absolute;
    top: 0;
    left: 0;
    background-color: #fff;
    border:1px solid #ccc;
    padding: 5px;
}

2.创建光线投射Raycaster实例

为了大家方便对照官方文档学习,所以我直接引用了官文文档的源码,大家可以对照官文修改代码进行实验加深理解 

官网地址:https://threejs.org/docs/index.html#api/zh/core/Raycaster

        1.创建 Raycaster 实例 

const raycaster = new THREE.Raycaster();
 //创建一个二维向量为后面 Raycaster 实例调用 .setFromCamera 方法做准备
const pointer = new THREE.Vector2();

          2.为窗口绑定事件 pointermove 想使用点击事件 click 的可以自行修改

window.addEventListener('pointermove', onPointerMove);

        3.定义窗口触发 pointermove 事件所执行的回调函数 onPointerMove 

const infoBox = document.querySelector('#infoBox') //获取Dom元素
const onPointerMove = (event) => {  //如果不使用箭头函数需要注意this指向问题
    // 修改 pointer 的值:将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
    pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
    pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
    //计算物体和射线的焦点
    // 方法 .intersectObjects ( objects : Array, recursive : Boolean, optionalTarget : Array ) : Array
    // 作用:检测所有在射线与这些物体之间,包括或不包括后代的相交部分。返回结果时,相交部分将按距离进行排序,最近的位于第一个),
    //      相交部分和.intersectObject所返回的格式是相同的。
    const intersects = raycaster.intersectObjects(this.scene.children);//返回和射线相交的一组物体,值为数组
    //没有相交物体时
    if (intersects.length === 0) {
        console.log('隐藏');
        infoBox.style.display = "none";
        return;
    }
    //有相交物体时
    if (intersects.length > 0) { //其中数组第一个值的 object属性值就是鼠标放在屏幕上离我们最近的模型
        console.log('显示');
        //设置信息
        infoBox.innerHTML = `长:${intersects[0].object.geometry.parameters.depth}
        <br>宽:${intersects[0].object.geometry.parameters.width}<br>
        高:${intersects[0].object.geometry.parameters.height}`;
        infoBox.style.display = "block";
        console.log(event.clientX);
        infoBox.style.left = event.clientX + "px"; //记得一定要拼接 px 我就是开始忘记了,导致信息框不移动
        infoBox.style.top = event.clientY + "px"
    }
}

        4.通过摄像机和鼠标位置更新射线

raycaster.setFromCamera(pointer, this.camera);

以上就是 光线投射Raycaster 的使用步骤


完整代码如下:

<template>
    <div ref="container">
        <div id="infoBox"></div>
    </div>
</template>

<script>
import * as THREE from "three";
import {OrbitControls} from "three/addons/controls/OrbitControls.js";

export default {
    name: "model",
    data() {
        return {
            //场景
            scene: null,
            //摄影机
            camera: null,
            //渲染器
            renderer: null,
            //相机控件
            controls: null,
        }
    },
    mounted() {
        // 调用方法创建场景、相机、渲染器和相机控件
        this.createScene();
        this.createCamera();
        this.createRenderer();
        this.createControls();

        // 创建两个不同大小的立方体模型,材质使用不受光照影响的 MeshBasicMaterial 材质
        const cube1 = new THREE.Mesh(
            new THREE.BoxGeometry(3, 2, 1),
            new THREE.MeshBasicMaterial({color: 0xff0000})
        );
        const cube2 = new THREE.Mesh(
            new THREE.BoxGeometry(1, 2, 3),
            new THREE.MeshBasicMaterial({color: 0x00ff00})
        );
        cube1.position.set(-2, 0, 0);
        cube2.position.set(2, 0, 0);
        this.scene.add(cube1, cube2);

        //1.创建 Raycaster 实例
        const raycaster = new THREE.Raycaster();
        const pointer = new THREE.Vector2(); //创建一个二维向量为后面 Raycaster 实例调用 .setFromCamera 方法做准备
        //3.定义窗口触发 pointermove 事件所执行的回调函数 onPointerMove
        const infoBox = document.querySelector('#infoBox') //获取Dom元素
        const onPointerMove = (event) => {  //如果不使用箭头函数需要注意this指向问题
            // 修改 pointer 的值:将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
            pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
            pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
            //计算物体和射线的焦点
            // 方法 .intersectObjects ( objects : Array, recursive : Boolean, optionalTarget : Array ) : Array
            // 作用:检测所有在射线与这些物体之间,包括或不包括后代的相交部分。返回结果时,相交部分将按距离进行排序,最近的位于第一个),
            //      相交部分和.intersectObject所返回的格式是相同的。
            const intersects = raycaster.intersectObjects(this.scene.children);//返回和射线相交的一组物体,值为数组
            //没有相交物体时
            if (intersects.length === 0) {
                console.log('隐藏');
                infoBox.style.display = "none";
                return;
            }
            //有相交物体时
            if (intersects.length > 0) { //其中数组第一个值的 object属性值就是鼠标放在屏幕上离我们最近的模型
                console.log('显示');
                //设置信息
                infoBox.innerHTML = `长:${intersects[0].object.geometry.parameters.depth}
        <br>宽:${intersects[0].object.geometry.parameters.width}<br>
        高:${intersects[0].object.geometry.parameters.height}`;
                infoBox.style.display = "block";
                console.log(event.clientX);
                infoBox.style.left = event.clientX + "px"; //记得一定要拼接 px 我就是开始忘记了,导致信息框不移动
                infoBox.style.top = event.clientY + "px"
            }
        }
        //2.为窗口绑定事件 pointermove 想使用点击事件 click 的可以自行修改
        window.addEventListener('pointermove', onPointerMove);

        const render = () => {
            // 4.通过摄像机和鼠标位置更新射线
            raycaster.setFromCamera(pointer, this.camera);
            //手动更改相机的变换后,必须调用controls.update()
            this.controls.update()
            this.renderer.render(this.scene, this.camera);
            requestAnimationFrame(render);
        };
        render();
    },
    methods: {
        //创建场景
        createScene() {
            this.scene = new THREE.Scene();
        },
        //创建相机
        createCamera() {
            this.camera = new THREE.PerspectiveCamera(
                45,
                window.innerWidth / window.innerHeight,
                1,
                1000
            );
            this.camera.position.set(0, 0, 5);
        },
        //创建渲染器
        createRenderer() {
            this.renderer = new THREE.WebGLRenderer({antialias: true}); //antialias:是否执行抗锯齿,默认为false.
            this.renderer.setSize(window.innerWidth, window.innerHeight);
            this.$refs.container.appendChild(this.renderer.domElement);
        },
        //创建相机控件
        createControls() {
            this.controls = new OrbitControls(this.camera, this.renderer.domElement);
        }
    }
};
</script>

<style scoped>
#infoBox {
    display: none;
    position: absolute;
    top: 0;
    left: 0;
    background-color: #fff;
    border: 1px solid #ccc;
    padding: 5px;
}
</style>

效果图如下 :


 结尾

要是读者觉得帮到你们了,麻烦点个赞鼓励一下,以便鼓舞我这个新手小白,谢谢大家

另外大家要有什么疑问或者是指教都可以在评论区发出来,作者看到一定回复,谢谢大家

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Three.js中光线投射Raycaster的简单使用案例 与模型的交互,当鼠标移动到模型时出现信息框 的相关文章

  • Jquery 悬停卡

    我在用着http designwithpc com Plugins Hovercard http designwithpc com Plugins Hovercard 但我不知道如何在悬停卡上声明 var 每个工作描述都有自己的 ID 当悬
  • JavaScript 添加布尔值

    console log true true 2 console log typeof true true number console log isNaN true true false 为什么两个布尔类型相加会产生一个数字 我有点理解 如
  • 在特定页面上执行 javascript 的正确“Rails”方式

    我试图在特定页面上运行 javascript 而我唯一的解决方案似乎是反模式 我有controller js内部生成的assets javascripts 我在用着gem jquery turbolinks 我的代码类似于以下内容 docu
  • 位置特征检测:固定

    我正在尝试找到一个脚本来检测设备是否放置position fixed元素相对于视口而不是整个文档 目前 标准桌面浏览器和 Mobile Safari 适用于 iOS 5 都是这样做的 而 Android 设备则相对于整个文档放置固定元素 我
  • Angular.js:如何从无序列表中获取 orderBy 或过滤器来工作?

    尝试根据价格和评级 在返回的对象中 进行排序 我宁愿用 ng click 和 li 来代替使用选择菜单 有没有办法做到这一点 我环顾四周 这是我能想到的最接近的 ul class restaurant filter li i class i
  • .push() 将多个对象放入 JavaScript 数组中返回“未定义”

    当我将项目添加到beats数组然后console log用户时 我得到了数组中正确的项目数 但是当我检查 length 时 我总是得到 1 尝试调用索引总是会给我 未定义 如下所示 Tom beats 1 我想我错过了一些明显的东西 但这让
  • 使用 Node.js 构建网站的最佳实践

    这个问题的答案是社区努力 help privileges edit community wiki 编辑现有答案以改进这篇文章 目前不接受新的答案或互动 我想知道如何使用 Node js 从头开始 开发一个网站 我明白我怎么能possibly
  • 导航栏下拉菜单(折叠)在 Bootstrap 5 中不起作用

    我在尝试使用以下命令创建响应式菜单或下拉按钮时遇到问题Bootstrap 5一切似乎都正常 导航图标和下拉图标出现 但它不起作用 当我单击nav图标或dropdown按钮 无dropdown menu apears 我想特别提到的是 我还包
  • 将 Firebase 云消息传递与 Windows 应用程序结合使用

    我在 Android 和 iOS 应用程序中使用 Firebase Cloud Messaging 但是我还有此应用程序的 Windows Mac OS 版本 我想保留相同的逻辑 我知道 Firebase Cloud Messaging 可
  • 使用 JavaScript 移动页面上的按钮

    我的按钮可以移动 但奇怪的是 我无法弄清楚偏移是否有问题 我希望我的按钮随着鼠标光标移动 但现在它的移动方式不是我想要的 有时它会消失 另外 创建的新按钮是重叠的 我不知道如何解决这个问题并拥有更好的外观 var coorA var coo
  • 如何始终将焦点保持在文本框中

    我创建了一个包含两个 div 的 HTML 页面 左侧的 div 页面的 90 是 ajax 结果的目标 右侧的 div 页面的 10 包含一个文本框 该页面的想法是在文本框中输入零件编号 通过条形码扫描仪 并显示与该零件编号匹配的绘图 显
  • 如何正确取消引用然后删除 JavaScript 对象?

    我想知道从内存中完全取消引用 JavaScript 对象的正确方法 确保删除时不会在内存中悬空 并且垃圾收集器会删除该对象 当我看这个问题时在 JavaScript 中删除对象 https stackoverflow com questio
  • 如何计算特定字符在字符串中出现的次数

    我正在尝试创建一个函数来查看数组中的任何字符是否在字符串中 如果是 有多少个 我尝试计算每一种模式 但是太多了 我尝试使用 Python 中的 in 运算符的替代方案 但效果不佳 function calc fit element var
  • LeafleteachLayer函数不会迭代所有Layer

    使用 GeoJSON 数据数组创建一些标记 getJSON GetLocationsServlet function data L geoJSON data onEachFeature onEachFeature addTo mymap G
  • Vaadin 12 将对象传递给 JavaScript 函数:无法对类进行编码

    Vaadin 12 Kotlin 项目 In my myPage html我有JavaScript myObject redirectToCheckout sessionId 1111 2222 所以我需要调用javaScript函数red
  • 使用 Jade 评估自定义 javascript 方法 (CircularJSON)

    我想通过 Jade 将一个对象解析为客户端 JavaScript 通常这会起作用 script var object JSON parse JSON stringify object but my object is circular ht
  • 主页(网格)上的缩略图现在显得模糊。如何纠正?

    我不知道这看起来是否愚蠢 但从早上开始我就无法纠正这个突然出现在我的博客网站上的错误www candidopinions in http www candidopinions in 我有一个网格视图模板 其中博客文章中的特色图像作为调整大小
  • 有没有办法使用 ko.observableArray 作为地图?

    有没有办法使用ko observableArray http knockoutjs com documentation observableArrays html像地图 字典一样 例如 var arr ko observableArray
  • 如何从 json 文件创建模型? (ExtJS)

    这是我想使用 json 文件创建的模型 Ext define Users extend Ext data Model fields name user id type int name user name type string 为了根据服
  • 将数组从 jquery ajax 传递到代码后面

    我必须将二维数组传递给在asp net网页代码后面编写的页面方法我有一个变量objList作为二维数组 我使用以下代码来实现此目的 但没有成功 并且未调用页面方法 脚本语言 function BindTable objList ajax u

随机推荐