当前位置: 首页 > news >正文

Threejs之球发射实战

本文目录

  • 前言
  • 一、效果预览
  • 二、代码实现及解析
    • 2.1 代码
    • 2.2 解析

前言

本篇将基于Threejs之模拟小球反弹基础上以及Threejs这个专栏学习过的知识点上进行小球更加真实的物理运动轨迹,并且还会与鼠标进行交互的操作。由于知识点都在上篇均有涉及,本篇就不过多赘述了。

一、效果预览

最终效果预览:
请添加图片描述
可以看到,我们完成鼠标点击生成小球,并且小球带有阴影以及贴合现实世界的物理行为,下落,旋转,碰撞。


二、代码实现及解析

2.1 代码

废话不多说直接上代码:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>html,body {margin: 0;padding: 0;width: 100%;height: 100%;}</style>
</head><body><script type="module">// 倒入轨道控制器import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';import * as THREE from "three";import * as CANNON from "cannon";// 创建场景const scene = new THREE.Scene();scene.background = new THREE.Color(0xffffff);// 创建相机const camera = new THREE.PerspectiveCamera( // 透视相机45, // 视角 角度数window.innerWidth / window.innerHeight, // 宽高比 占据屏幕0.1, // 近平面(相机最近能看到物体)1000, // 远平面(相机最远能看到物体));camera.position.set(0, 2, 20);// 创建渲染器const renderer = new THREE.WebGLRenderer({antialias: true, // 抗锯齿});// 设置渲染器宽高renderer.setSize(window.innerWidth, window.innerHeight);// renderer(渲染器)的dom元素添加到我们的HTML文档中document.body.appendChild(renderer.domElement);// 加入灯光const light = new THREE.PointLight( 0xffffff, 1000, 100 );light.position.set(0,20,0);const pointLightHelper = new THREE.PointLightHelper( light, 1 );scene.add( pointLightHelper );scene.add( light );const ambientLight = new THREE.AmbientLight( 0x404040, 100 ); // 柔和的白光scene.add( ambientLight );// 地面const plane = new THREE.Mesh(new THREE.PlaneGeometry(40, 40),new THREE.MeshStandardMaterial({color: 0x817936}));plane.rotation.x = -Math.PI/2;// 添加到场景中scene.add(plane);renderer.shadowMap.enabled = true;plane.receiveShadow = true;light.castShadow = true;// 创建物理世界const physicsWorld = new CANNON.World();// 设置y轴重力physicsWorld.gravity.set(0, -9.82, 0);// 创建物理材料const groundMaterial = new CANNON.Material('groundMaterial');const sphereMaterial = new CANNON.Material('sphereMaterial');const contactMaterial = new CANNON.ContactMaterial(groundMaterial, sphereMaterial, {restitution: 0.7 // 弹性});physicsWorld.addContactMaterial(contactMaterial);// 创建物理地面const groundBody = new CANNON.Body({mass: 0, // 为0表示地面不受重力影响shape: new CANNON.Plane(), // 物体的形状,cannon中地面形状物体material: groundMaterial,});groundBody.quaternion.setFromEuler(-Math.PI / 2, 0, 0); // 将地面绕着x轴旋转90度成为真正的地面physicsWorld.addBody(groundBody);// 加载贴图const loader = new THREE.TextureLoader();const texture = loader.load("../images/rabbit.png")// 多个小球,创建小球数组let spheresArr = [];// 动态生成小球const createSphere = (position, direction) => { // 接收两个参数 position:小球生成的位置,direction小球超哪发射位置const radius = 1;// 创建可视化小球const geometry = new THREE.Mesh(new THREE.SphereGeometry(radius, 32, 32), new THREE.MeshPhongMaterial({map: texture}));geometry.castShadow = true;geometry.position.copy(position);scene.add(geometry);// 创建物理小球刚体const sphereBody = new CANNON.Body({mass: 0.5, // 质量设为1material: sphereMaterial,linearDamping: 0.5, // 模拟空气阻力});// 创建物理小球const sphereShape = new CANNON.Sphere(radius);sphereBody.position.copy(position);sphereBody.addShape(sphereShape); // 刚体添加形状也可这种写法sphereBody.applyLocalForce(direction.scale(600), // 施加的力的向量new CANNON.Vec3(0, 0, 0) // 力作用的点在刚体的局部坐标系中的位置); // 在刚体的局部坐标系中的指定点上施加一个力physicsWorld.addBody(sphereBody);spheresArr.push({geometry,sphereBody})}renderer.domElement.addEventListener('mouseup', (event) => {// console.log(spheresArr);const mouse = new THREE.Vector2();mouse.x = (event.clientX / window.innerWidth) * 2 - 1;mouse.y = -(event.clientY / window.innerWidth) *2 + 1;const raycaster = new THREE.Raycaster();raycaster.setFromCamera(mouse,camera);const pos = new THREE.Vector3();pos.copy(raycaster.ray.direction); // 鼠标点击的射线方向pos.add(raycaster.ray.origin); // 射线原点const direction = new CANNON.Vec3(raycaster.ray.direction.x,raycaster.ray.direction.y,raycaster.ray.direction.z,)createSphere({x:pos.x, y:pos.y, z:pos.z}, direction);})const updatePhysic = () => { // 因为这是实时更新的,所以需要放到渲染循环动画animate函数中physicsWorld.step(1/60);spheresArr.forEach(({geometry,sphereBody}) => {geometry.position.copy(sphereBody.position); // 将物理刚体小球的位置赋值给threejs的小球geometry.quaternion.copy(sphereBody.quaternion); // 将物理刚体小球的旋转赋值给threejs的小球})}// 控制器const control = new OrbitControls(camera, renderer.domElement);// 开启阻尼惯性,默认值为0.05control.enableDamping = true;// 渲染循环动画function animate() {// 在这里我们创建了一个使渲染器能够在每次屏幕刷新时对场景进行绘制的循环(在大多数屏幕上,刷新率一般是60次/秒)requestAnimationFrame(animate);updatePhysic();// 更新控制器。如果没在动画里加上,那必须在摄像机的变换发生任何手动改变后调用control.update();renderer.render(scene, camera);};// 执行动画animate();</script>
</body>
</html>

2.2 解析

重点代码解析:

  1. 小球阴影:重点添加灯光,以及受灯光影响的材质。const light = new THREE.PointLight( 0xffffff, 1000, 100 );添加点光源。地面为受灯光影响的new THREE.MeshStandardMaterial({color: 0x817936})材质以及小球受灯光影响材质ew THREE.MeshPhongMaterial({map: texture})。并且打开阴影开光:
    renderer.shadowMap.enabled = true;
    plane.receiveShadow = true;
    light.castShadow = true;
    geometry.castShadow = true;
    
  2. 动态交互事件renderer.domElement.addEventListener('mouseup', callback)这是鼠标交互的关键。
  3. 每次点击都动态生成可视小球及刚体小球,并且都放到数组里:
         spheresArr.push({geometry,sphereBody})
    
  4. 获取鼠标点击时的二维向量
    	const mouse = new THREE.Vector2();mouse.x = (event.clientX / window.innerWidth) * 2 - 1;mouse.y = -(event.clientY / window.innerWidth) *2 + 1;
    
  5. 射线方向及射线原点
    	const raycaster = new THREE.Raycaster();raycaster.setFromCamera(mouse,camera);const pos = new THREE.Vector3();pos.copy(raycaster.ray.direction); // 鼠标点击的射线方向pos.add(raycaster.ray.origin); // 射线原点const direction = new CANNON.Vec3(raycaster.ray.direction.x,raycaster.ray.direction.y,raycaster.ray.direction.z,)          
    

在学习的路上,如果你觉得本文对你有所帮助的话,那就请关注点赞评论三连吧,谢谢,你的肯定是我写博的另一个支持。

相关文章:

Threejs之球发射实战

本文目录 前言一、效果预览二、代码实现及解析2.1 代码2.2 解析 前言 本篇将基于Threejs之模拟小球反弹基础上以及Threejs这个专栏学习过的知识点上进行小球更加真实的物理运动轨迹&#xff0c;并且还会与鼠标进行交互的操作。由于知识点都在上篇均有涉及&#xff0c;本篇就不过…...

详解新规|逐条分析《电子认证服务管理办法(征求意见稿)》修订重点

近日&#xff0c;工信部就《电子认证服务管理办法&#xff08;征求意见稿&#xff09;》公开征求意见。 来源&#xff5c;公开资料 图源&#xff5c;Pixabay 编辑&#xff5c;公钥密码开放社区 《电子认证服务管理办法》&#xff08;以下简称《办法》&#xff09;于2009年2…...

哪个编程工具让你的工作效率翻倍?

✍️作者简介&#xff1a;小北编程&#xff08;专注于HarmonyOS、Android、Java、Web、TCP/IP等技术方向&#xff09; &#x1f433;博客主页&#xff1a; 开源中国、稀土掘金、51cto博客、博客园、知乎、简书、慕课网、CSDN &#x1f514;如果文章对您有一定的帮助请&#x1f…...

SEW变频器的特点

SEW变频器是德国SEW-EURODRIVE GmbH公司生产的一种变频器产品&#xff0c;该公司是全球领先的驱动技术和系统解决方案提供商之一。以下是关于SEW变频器的详细介绍&#xff1a; 一、产品特点 高效节能&#xff1a;SEW变频器采用先进的电力电子技术和控制技术&#xff0c;能够实…...

大象机械人------1、关节控制

回到首页 目录 1 单关节控制 角度控制&#xff1a;1.1 send_angle(id, degree, speed)电位值控制&#xff1a;1.2 set_encoder(joint_id, encoder) 2 多关节控制 获取所有角度&#xff1a;2.1 get_angles()角度控制&#xff1a;2.2 send_angles(degrees, speed)电位值控制&…...

油电叉车倒车防撞报警系统精准探测

油电叉车倒车防撞报警系统通过集成最新的传感器技术、图像识别算法以及智能控制技术‌&#xff0c;通过实时监测叉车周围环境中的障碍物、行人和其他叉车&#xff0c;及时发出警报&#xff0c;避免可能的碰撞事故。 油电叉车倒车防撞报警系统功能详解 精准探测 叉车倒车时&a…...

Java学习路线:从零基础到高级开发者的完整指南

初学者入门指南 1. 环境搭建 安装JDK: 下载并安装最新版本的JDK&#xff08;Java Development Kit&#xff09;。配置环境: 设置JAVA_HOME环境变量&#xff0c;并将bin目录添加到PATH中。选择IDE: 使用Eclipse、IntelliJ IDEA或其他任何你喜欢的Java集成开发环境。 2. Java基…...

【Java算法】递归

&#x1f525;个人主页&#xff1a; 中草药 &#x1f525;专栏&#xff1a;【算法工作坊】算法实战揭秘 &#x1f347;一.递归 概念 递归是一种解决问题的方法&#xff0c;其中函数通过调用自身来求解问题。这种方法的关键在于识别问题是否可以被分解为若干个相似但规模更小…...

NIDS——suricata(三)

一、监控ICMP流量 1、ICMP流量特征 四大特征分别为&#xff1a;消息类型&#xff08;Type&#xff09;、代码&#xff08;Code&#xff09;、校验和&#xff08;Checksum&#xff09;、数据字段&#xff08;Data Field&#xff09;。这里我们使用 type消息类型。 ICMP 消息的类…...

运动耳机哪个牌子最好用?年度精选五款好用的骨传导耳机推荐

相信大家都已经深有体会&#xff0c;拿那种常规的入耳式无线蓝牙耳机来做运动耳机&#xff0c;很难满足运动需要。如果选择前两年流行的颈挂式无线运动蓝牙耳机&#xff0c;虽然简单轻巧&#xff0c;但也是入耳式设计&#xff0c;长时间佩戴耳朵不舒服。这样看来&#xff0c;运…...

鞋服企业信息化建设若干架构分享

鞋服企业的信息化建设有着自身的一些特点&#xff0c;这些特点主要体现在以下几个方面&#xff1a; 集成化&#xff1a;鞋服企业的信息化建设往往需要集成多种系统&#xff0c;如企业资源规划系统&#xff08;ERP&#xff09;、客户关系管理系统&#xff08;CRM&#xff09;、供…...

比较顺序3s1和3s2的搜索难度

在行列可自由变换的平面上&#xff0c;3点结构只有6个 (A,B)---6*30*2---(0,1)(1,0) 分类A和B&#xff0c;让A是6个3点结构&#xff0c;让B全是0。当收敛误差为7e-4&#xff0c;收敛199次取迭代次数平均值&#xff0c; 让训练集A-B矩阵的高分别是3&#xff0c;4&#xff0c;5…...

Vue3 el-switch @change事件在初始化时会自动调用问题

接收一个vue3项目&#xff0c;突然有一天&#xff0c;table里有个switch开关&#xff0c;请求数据之后就开始执行switch的change事件&#xff0c;我还啥都没操作&#xff0c;就报一推重复请求 <template><el-switch v-model"rec" inline-prompt :active-val…...

全面解析性能测试中的瓶颈分析与优化策略!

在软件开发的生命周期中&#xff0c;性能测试是确保应用程序在不同负载下稳定运行的关键步骤。性能瓶颈是导致系统性能下降的主要原因&#xff0c;及时发现并解决这些瓶颈&#xff0c;能够显著提升系统的响应速度和用户体验。本文将深入探讨性能测试中的瓶颈分析方法与优化策略…...

2018年Android面试题含答案--适合中高级(下)

熟悉Android系统的童鞋都知道&#xff0c;系统出于体验和性能上的考虑&#xff0c;app在退到后台时系统并不会真正的kill掉这个进程&#xff0c;而是将其缓存起来。打开的应用越多&#xff0c;后台缓存的进程也越多。在系统内存不足的情况下&#xff0c;系统开始依据自身的一套…...

基于SSM的汽车租赁系统+LW示例参考

系列文章目录 1.基于SSM的洗衣房管理系统原生微信小程序LW参考示例 2.基于SpringBoot的宠物摄影网站管理系统LW参考示例 3.基于SpringBootVue的企业人事管理系统LW参考示例 4.基于SSM的高校实验室管理系统LW参考示例 5.基于SpringBoot的二手数码回收系统原生微信小程序LW参考示…...

[晕事]今天做了件晕事44 wireshark 首选项IPv4:Reassemble Fragented IPv4 datagrams

不知不觉&#xff0c;已经来到了晕事系列的第四十四个晕事。今天办的晕事和Wireshark查看网络包相关。说&#xff0c;在Wireshark的编辑-首选项协议里的IPv4协议&#xff0c;有一个参数设置是&#xff1a;Reassemble Fragented IPv4 datagrams。 这个参数的含义是指定Wireshar…...

Unity人工智能开发学习心得

在Unity中进行人工智能研究与应用主要集中在几个关键领域&#xff0c;包括使用Unity ML-Agents插件进行强化学习、利用神经网络技术和深度学习技术训练AI&#xff0c;以及基于行为树技术设计游戏人工智能。 ‌使用Unity ML-Agents插件进行强化学习‌&#xff1a;Unity ML-Agent…...

0911,类与类之间的关系,设计原则,工厂模式

01_figure.cc //简单工厂 #include <math.h> #include <iostream> #include <string> #include <memory>using std::cout; using std::endl; using std::string; using std::unique_ptr;//-------------------------------------------------// /…...

【2024最新版】零基础Python快速入门篇

完整代码已打包&#xff0c;需要的小伙伴可以戳这里 [学习资料] 安装和运行 1.安装 要使用"Python"首先要把它安装到你电脑里。打开 [Python官网]下载安装包。 在Windows上安装 打开安装包&#xff0c;选择"Use admin privileges when installing py.exe&qu…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

stm32G473的flash模式是单bank还是双bank?

今天突然有人stm32G473的flash模式是单bank还是双bank&#xff1f;由于时间太久&#xff0c;我真忘记了。搜搜发现&#xff0c;还真有人和我一样。见下面的链接&#xff1a;https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

centos 7 部署awstats 网站访问检测

一、基础环境准备&#xff08;两种安装方式都要做&#xff09; bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats&#xff0…...

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; 思路 使用两个栈&#xff1a;一个存储重复次数&#xff0c;一个存储字符串 遍历输入字符串&#xff1a; 数字处理&#xff1a;遇到数字时&#xff0c;累积计算重复次数左括号处理&#xff1a;保存当前状态&a…...

系统设计 --- MongoDB亿级数据查询优化策略

系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log&#xff0c;共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题&#xff0c;不能使用ELK只能使用…...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例&#xff0c;模拟20个网页的爬取&#xff0c;每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程&#xff1a;允许程序同时执行多个任务&#xff0c;提高IO密集型任务&#xff08;如网络请求&#xff09;的效率…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)

文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...