three.js 学习笔记 | 光线投射技术 - 包围盒(碰撞检测)

文章目录

  • three.js 学习笔记
    • 光线投射技术实现3D场景交互事件 THREE.Raycaster
      • 坐标系的转换
      • 案例:选中的模型变为红色
    • 包围盒Box3 - 碰撞检测
      • AABB包围盒辅助器Box3Helper
        • 案例1:创建AABB包围盒/包围球
          • computeBoundingBox与boundingBox 搭配使用,创建包围盒
          • box3的常用场景

three.js 学习笔记

光线投射技术实现3D场景交互事件 THREE.Raycaster

语法:new THREE.Raycaster()
作用:光线投射用于进行鼠标拾取(在三维空间中计算出鼠标移过了什么物体)
参数
origin:光线投射的原点向量。
direction:向射线提供方向的方向向量(归一化)

向量归一化:将向量的方向保持不变,大小归一化到1。
在这里插入图片描述在这里插入图片描述

Raycaster对象的属性及方法

属性及方法参数描述
setFromCamera ( coords : Vector2, camera : Camera ) : undefinedcoords:在标准化设备坐标中鼠标的二维坐标(x,y分量在-1,1之间)
camera:射线来源的相机
使用一个新的原点和方向来更新射线
intersectObjects ( objects : Array, recursive : Boolean, optionalTarget : Array ) : Arrayobjects:检测和射线相交的一组物体。
recursive :检测物体本身外,是否同时检测所有物体的后代。默认值为true。
optionalTarget:设置存储结果的目标数组,最后返回的也是这个数组,如果没有设置则每次调用都会初始化一个新数组。采用push的方式向数组中添加,所以如果设置的是全局数组会不断的向里面push新元素

返回值:相交对象组成的数组
检测射线与这些物体之间是否有相交点

鼠标拾取(射线追踪法)
场景最终被输出在一个画布canvas元素上,所以没办法获取鼠标hover处模型的DOM对象。
在2D中,判断鼠标是否选中的标准是鼠标位置是否在该区域中。在3D场景中,由于屏幕是2D显示的,判断选中的标准是从相机为起点位置穿过鼠标位置的射线是否也穿过模型,如果穿过则认为该模型被选中。
在这里插入图片描述

坐标系的转换

  • 三维空间的坐标系:屏幕中心为原点,坐标取值范围(-1,1)
  • 页面的二维坐标:左上角为原点,取值范围是按照屏幕大小的实际像素位置来获取(x, y)。

三维空间的坐标系(世界坐标)
屏幕中心为原点,坐标取值范围(-1,1)
在这里插入图片描述

页面的二维坐标系
左上角为原点,取值范围是按照屏幕大小的实际像素位置来获取(x, y)。
在这里插入图片描述
转换步骤

  1. 鼠标位置(x1,y1)是二维画面中的坐标位置

    鼠标位置(x1,y1) = (event.clientX, event.clientY)

  2. 在鼠标拾取时,需要将该坐标转换为中间位置(x2,y2),该中间位置以屏幕中心为原点,实际像素为x和y

    在二维页面中,屏幕中点的位置是(innerWidth / 2, innerHeight / 2)。可以得到任意点(x1,y1)的中间位置 x2 = x1 - (innerWidth / 2)y2 = (innerHeight / 2) - y1
    在这里插入图片描述

  3. 由于三维坐标系中x与y分量的取值范围是(-1,1),所以需要将(x2,y2)归一化处理得到(x3,y3)

    考虑极端点`(x2,y2) = (w/2,h/2)`对应的`(x3,y3)=(1,1)` 
    x3 = (x2  / (w/2))
    = (  ( x1 -  ( w/2 )  ) /  (w/2) )
    =  (2   x1 / w) - 1
    = (x1 / w)* 2 - 1 
    同理得到 y3 = - ( y1 /  h) * 2  + 1将x1与y1待入可得 鼠标点击位置在三维坐标系中的坐标
    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
    

案例:选中的模型变为红色

方法:intersectObjects ( objects : Array, recursive : Boolean, optionalTarget : Array ) : Array 检测射线与这些物体之间是否有相交点
参数
objects:检测和射线相交的一组物体。
recursive :检测物体本身外,是否同时检测所有物体的后代。默认值为true。
optionalTarget:设置存储结果的目标数组,最后返回的也是这个数组,如果没有设置则每次调用都会初始化一个新数组。采用push的方式向数组中添加,所以如果设置的是全局数组会不断的向里面push新元素
返回值:相交对象组成的数组

相交对象的属性描述
distance相机到相交对象交点的距离
face相交对象(鼠标点击的物体)面的信息
normal:Vector3相交点的法线向量
object相交对象
point:Vector3交点的坐标
uv
const sphere1 = new THREE.Mesh(new THREE.SphereGeometry(25, 32,32), new THREE.MeshBasicMaterial ({color: 0x00ff00,
}));
sphere1.position.x= -140;
scene.add(sphere1);const sphere2 = new THREE.Mesh(new THREE.SphereGeometry(25, 32,32), new THREE.MeshBasicMaterial ({color: 0x0000ff,
}));
scene.add(sphere2);const sphere3 = new THREE.Mesh(new THREE.SphereGeometry(25, 32,32), new THREE.MeshBasicMaterial ({color: 0xff00ff,
}));
sphere3.position.x= 140;
scene.add(sphere3);scene.add(new THREE.AxesHelper(100));// 创建射向
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
// 监听鼠标移动
window.addEventListener('click', (event) => {//设置鼠标在三维坐标系中的点击位置x,ymouse.x = (event.clientX / window.innerWidth) * 2 - 1;mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;console.log(mouse)
})

包围盒Box3 - 碰撞检测

包围盒是一个简单的几何空间,里面包含着复杂形状的物体。
为物体添加包围体的目的是快速的进行碰撞检测或者进行精确的碰撞检测之前进行过滤(即当包围体碰撞,才进行精确碰撞检测和处理)。

包围盒广泛地应用于①碰撞检测②摄像机视锥体的可见性判断,每一个物体都有自己的包围盒。因为包围盒一般为规则物体,因此用它来代替物体本身进行计算,会比直接用物体本身更加高效和简单。

在这里插入图片描述

常见包围盒描述特点
轴对齐包围盒(AABB)与坐标轴是对齐的,但不随物体旋转(图1刚好最小包围盒,图2老虎旋转了一个角度后,AABB包围盒便增加了较大的空隙)总是与世界坐标系(固定)的三个轴平行
有向包围盒(OBB)始终沿着物体的主成分方向生成最小的一个矩形包围盒,可以随物体旋转,可用于较精确的碰撞检测与物体局部坐标系(经常变换的坐标系)的三个轴平行

AABB包围盒辅助器Box3Helper

AABB包围盒的简单介绍
AABB盒:一个3D的AABB就是一个简单的六面体,每一边都平行于一个坐标平面,它的长、宽、高可以彼此不同。外边界是一个规整的形状,所以只需要两个坐标就能计算出该形状。
特别重要的两个顶点为:Pmin = [Xmin Ymin Zmin]Pmax = [ Xmax Ymax Zmax](最小点一般是左后下方的点,最大点是右前上方的一个点)

AABB内的点满足以下条件
xmin≤x≤xmax
ymin≤y≤ymax
zmin≤z≤zmax

Box3的介绍
Box3类表示与三维空间中的一个轴对齐包围盒(axis-aligned bounding boxAABB
构造函数Box3( min : Vector3, max : Vector3 )

  • min:Vector3 可选,表示包围盒的下边界。 默认值是(+ Infinity, + Infinity, + Infinity )
  • max:Vector3 可选,表示包围盒的上边界。 默认值是( - Infinity, - Infinity, - Infinity )

AABB包围盒辅助器Box3Helper
语法:new THREE.Box3Helper( box : Box3, color : Color )
box:被三维包围盒包围的物体参数Box3
color:可选表示线框盒子的颜色, 默认为0xffff00
作用:模拟3维包围盒 Box3 的辅助对象,创建一个新的线框盒子用以表示指定的3维包围盒。
继承链:Object3D → Line → LineSegments → Box3Helper

包围球没有辅助器,通过创建球来代替辅助器。

// 获取包围球
const sphere = bufferGeometry.boundingSphere;
// 创建辅助球
let sphereHelper = new THERE.SphereGeometry(sphere.radius)
let sphereHelperMaterial = new THERE.MeshBasicMaterial();
let sphereMesh = new THERE.Mesh(sphereHelper ,sphereHelperMaterial);
sphereMesh.position.copy(sphere.center)
scene.add(sphereMesh)
案例1:创建AABB包围盒/包围球
computeBoundingBox与boundingBox 搭配使用,创建包围盒

获取包围盒Box3bufferGeometry.boundingBox : Box3 ,获取当前 bufferGeometry 的外边界矩形,默认值是 null。
返回Box3:{max:{最大点的坐标},min:{最小点的坐标}}

计算被包围物体的包围盒bufferGeometry.computeBoundingBox(),计算当前几何体的边界矩形,该操作会更新已有boundingBox属性

为了可视化包围盒,我们会使用包围盒辅助器可视化包围盒,将bufferGeometry.boundingBox的值作为参数传递给包围盒辅助器Box3Helper的构造器参数。

const sphereGeometry = new THREE.SphereGeometry(50, 32, 32);
const sphereMaterial = new THREE.MeshBasicMaterial();
const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
scene.add(sphere);
// 计算包裹盒,并将结果设置给bufferGeometry.boundingBox
sphereGeometry.computeBoundingBox()
const box3Helper = new THREE.Box3Helper( sphereGeometry.boundingBox)
scene.add(box3Helper);

在这里插入图片描述

box3的常用场景
  1. 包围盒应用与被包围三维物体同样的变化矩阵,包围盒应用变换矩阵applyMatrix4
    包围盒会受物体的形态影响,比如物体进行了变换。包围盒也需要应用同样的变换bufferGeometry.boundingBox.applyMatrix4 ( matrix : Matrix4 )

    可能包围盒根据物体顶点计算出来?但是有些变换不改变几何体的顶点信息?所以需要手动进行世界矩阵更新·

    box3.applyMatrix4 ( matrix : Matrix4 ):将参数的变换矩阵应用在当前Box3上,包围盒8个顶点都会乘以这个变换矩阵。

    // 三维物体更新世界矩阵	
    mesh.updateWorldMatrix(true,true)
    // box - 需要复制的包围盒 Box3  应用几何体的变化矩阵mesh.matrixWorld
    box.copy( mesh.geometry.boundingBox ).applyMatrix4( mesh.matrixWorld );
    
  2. 让几何体居中 获取包围盒/包围球的中心位置 = 获取三维物体的中心位置
    几何体.center():根据边界矩形将几何体居中,本质就是获取包围盒/包围球的中心位置。
    box3.getCenter ( target : Vector3 ) : Vector3:获取包围盒的中心位置。 如果指定了target ,结果将会被拷贝到target,返回中心位置。

    //1.计算几何体包围盒
    bufferGeometry.computeBoundingBox()
    //2.设置几何体居中
    bufferGeometry.center();// 1.获取包围盒
    const box = bufferGeometry.boundingBox()
    // 2.获取包围盒的中心 打印法相两个值相等
    const center = box .getCenter()
    
  3. 获取多个物体的包围盒

    思路:循环每一个几何体,获取单个的几何体包围盒不断合并成一个大包围盒
    方法:box3.union ( box : Box3 ) : this :在 box 参数的上边界和已有box对象的上边界之间取较大者,而对两者的下边界取较小者,这样获得一个新的较大的联合盒子。
    box3.setFromObject ( object : Object3D ) : this 参数是需要计算包围盒的3D对象 Object3D。计算和世界轴对齐的一个对象 Object3D (含其子对象)的包围盒,计算对象和子对象的世界坐标变换。 该方法可能会导致一个比严格需要的更大的框。

    没理解这个是和世界轴对齐的包围盒AABB还是说物体对齐,对象和世界轴对齐是指什么意思?

    let box = new THREE.Box3
    for(let i=0;i<scene.children.length;i++){// 获取包围盒的方法1// ① 获取当前几何体的包围盒  如果有场景中有其他不相关东西需要排出一下scene.children[i].geometry.computeBoundingBox();// ② 获取包围盒let box3 = scene.children[i].geometry.boundingBox;// ③ 更新世界矩阵scene.children[i].updateWorldMatrix(true,true)box3.applyMatrix4(scene.children[i].metrixWorld)// 获取包围盒的方法2//②let box3 = new THREE.Box3().setFromObject (scene.children[i])//合并包围盒box.unioin(box3);
    }
    // 使用包围盒辅助器显示
    const box3Helper = new THREE.Box3Helper( box )
    scene.add(box3Helper);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/4215.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vivado Aurora 8B/10B IP核(1)

Aurora 8B/10B IP 支持 Kintex -7, Virtex -7 FPGA GTP 和 GTH 收发器&#xff0c;Artix -7 FPGA GTP 收发器, Zynq -7000 GTP and GTP 收发器。Aurora 8B/10B IP core 可以工作于单工或者全双工模式。IP CODE的使用也非常简单&#xff0c;支持 AMBA总线的 AXI4-Stream 协议。…

字符串函数及其模拟实现

目录 strlen函数介绍模拟实现 strcpy函数介绍模拟实现 strcat函数介绍模拟实现 strcmp函数介绍模拟实现 strncpy函数介绍模拟实现 strncat函数介绍模拟实现 strncmp函数介绍模拟实现 strtokstrstr函数介绍模拟实现 strerrorperror strlen 函数介绍 函数介绍&#xff1a; 字符串…

Leetcode 17. 电话号码的字母组合

给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 示例 1&#xff1a; 输入&#xff1a;digits “23” 输出&#xff1a;[“a…

React真的好难用

我发现React就像个宗教一样&#xff0c;网络上总有一群信徒。信徒&#xff1a;React天下第一&#xff0c;谁也不能说他不好。 网络上大佬对React的评价一般有几类&#xff1a; React跟Vue比就是手动档和自动档的区别&#xff0c;高手都开手动档。—— 就一个破打工的&#xf…

cJSON的使用

文章目录 一、CJSON初识二、CJSON解析器基础三、CJSON解析数据JSON解析基础CJSON解析数组数据CJSON解析嵌套数据 五、创建JSON数据 一、CJSON初识 JSON (JavaScript Object Notation)是一种轻量级的数据交换格式&#xff0c;常用于在网络之间传输数据。它是一种文本格式&#…

河南新办灌溉排涝乙级资质预算分析

河南新办灌溉排涝乙级资质的预算分析是一个涉及多方面因素的综合考量。以下是对该预算的详细分析&#xff1a; 首先&#xff0c;人员费用是预算中的重要组成部分。这包括聘请符合资质要求的技术人员、工程师和其他相关人员的薪酬、社保等费用。这些费用会根据所需人员的数量、资…

JavaScript云LIS系统源码 前端框架JQuery+EasyUI+后端框架MVC+SQLSuga大型医院云LIS检验系统源码 可直接上项目

JavaScript云LIS系统源码 前端框架JQueryEasyUI后端框架MVCSQLSuga大型医院云LIS检验系统源码 可直接上项目 云LIS系统概述&#xff1a; 云LIS是为区域医疗提供临床实验室信息服务的计算机应用程序&#xff0c;可协助区域内所有临床实验室相互协调并完成日常检验工作&#xff…

Unity类银河恶魔城学习记录15-5,6 p157 Audio time limiter p158 Area sound

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili​​ AreaSound.cs using System.Collections; using System.Collections.G…

视频输入c++ 调用 libtorch推理

1、支持GPU情况 libtorch 支持GPU情况比较奇怪&#xff0c;目前2.3 版本需要在链接器里面加上以下命令&#xff0c;否则不会支持gpu -INCLUDE:?ignore_this_library_placeholderYAHXZ 2 探测是否支持 加一个函数看你是否支持torch&#xff0c;不然不清楚&#xff0c;看到…

Hive函数详解

Hive 是一个建立在 Hadoop 上的数据仓库基础架构&#xff0c;它提供了类似于 SQL 的查询语言&#xff0c;称为 HiveQL&#xff0c;用于对存储在 Hadoop 分布式文件系统中的数据进行查询和分析。 1.函数简介 Hive会将常用的逻辑封装成函数给用户进行使用&#xff0c;类似于Jav…

Web前端开发 小实训(一) 成绩分类统计

用于学生web前端开发课程实训练习&#xff0c;掌握基本语法和数据类型 实训目的 使用分支语句&#xff0c;完成分数统计与等级对比,通过输入框输入分数&#xff0c;可以根据分数多少划分等级。 参考思路&#xff1a; 分析题目&#xff1a;根据输入分数进行等级划分。 操作过…

springboot如何使用RedisTemplate

第一步&#xff1a;创建一个spring boot项目 第二步&#xff1a;pom导入redis相关依赖 <!--reids依赖--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId> </depen…

Go语言中的goroutine调度是如何实现的?

文章目录 一、M:N调度模型二、GMP模型三、调度过程四、调度优化五、示例代码 在Go语言中&#xff0c;goroutine是一种轻量级的线程&#xff0c;它使得并发编程变得更加简单和高效。而goroutine的调度则是Go运行时&#xff08;runtime&#xff09;系统负责的一个核心任务&#x…

Postman,一个功能强大的API开发和测试工具

最近有小伙伴说在找 postman 的使用教程&#xff0c;案例等文章。 那么今天我就来写一个。 Postman 是一个功能强大的 API 开发和测试工具&#xff0c;它提供了丰富的功能&#xff0c;帮助开发人员更好地管理、测试和文档化 API。无论是单独开发还是团队协作&#xff0c;Postma…

[1688]jsp工资投放管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 工资投放管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0…

黑马面试篇

课程地址&#xff1a;新版Java面试专题视频教程&#xff0c;java八股文面试全套真题深度详解&#xff08;含大厂高频面试真题&#xff09;_哔哩哔哩_bilibili 课程名称&#xff1a;新版Java面试专题视频教程&#xff0c;java八股文面试全套真题深度详解&#xff08;含大厂高频…

Flutter - 折叠面板

demo 地址: https://github.com/iotjin/jh_flutter_demo 代码不定时更新&#xff0c;请前往github查看最新代码 flutter 自定义折叠组件 支持三种类型和两种展示效果可自定义title和被折叠的内容 效果图 示例 import package:flutter/material.dart; import /jh_common/widge…

基于SNAP使用SAR数据做变化检测change detection

基于SNAP使用SAR数据做变化检测change detection 1. 前言2. 步骤2.1 添加数据2.2 辐射定标--散斑过滤--地形矫正2.3 裁剪2.4 变化检测 3.查看变化检测结果 1. 前言 在SNAP中&#xff0c;change detection主要通过Stack工具来完成。 SAR数据&#xff1a;Radarsat-2 SLC 其他数据…

基于FastGPT搭建知识库问答系统

什么是 FastGPT &#xff1f; FastGPT 是一个基于 LLM 大语言模型的知识库问答系统&#xff0c;提供开箱即用的数据处理、模型调用等能力。同时可以通过 Flow 可视化进行工作流编排&#xff0c;从而实现复杂的问答场景&#xff01; FastGPT 允许用户构建本地知识库&#xff0c;…

MQTT数据传输Payload的常见格式介绍

使用MQTT client过程中看到常见的数据格式&#xff1a; 下面是介绍 Plaintext&#xff08;纯文本&#xff09; 介绍&#xff1a;纯文本编码是最基本的编码形式&#xff0c;它使用标准的ASCII或Unicode字符来表示数据。这种编码格式是人类可读的&#xff0c;因为它直接表示文本信…