Babylon.js學習之路《七、用戶交互:鼠標點擊、拖拽與射線檢測》

在這里插入圖片描述

文章目錄

  • 1. 引言:用戶交互的核心作用
    • 1.1 材質與紋理的核心作用
  • 2. 基礎交互:鼠標與觸摸事件
    • 2.1 綁定鼠標點擊事件
    • 2.2 觸摸事件適配
  • 3. 射線檢測(Ray Casting)
    • 3.1 射線檢測的原理
    • 3.2 高級射線檢測技巧
  • 4. 拖拽物體的實現
    • 4.1 拖拽基礎:平面拖拽
    • 4.2 3D 空間自由拖拽
    • 4.3 拖拽限制(軸向鎖定、范圍限制)
  • 5. 高級交互技巧
    • 5.1 組合交互:拖拽 + 旋轉/縮放
    • 5.2 交互反饋設計
    • 5.3 性能優化
  • 6. 實戰任務
    • 任務 1:實現可拖拽的拼圖游戲
    • 任務 2:射線檢測射擊游戲
  • 7. 常見問題與解決方案
    • 7.1 射線檢測不準確
    • 7.2 拖拽時物體穿透地面
  • 8. 總結與下一章預告
    • 8.1 關鍵知識點回顧
    • 8.2 下一章預告


1. 引言:用戶交互的核心作用

  • 上一章詳解燈光與陰影,材質與紋理的相關知識。
  • 這一章詳細介紹一下Babylon中,用戶交互:鼠標點擊、拖拽與射線檢測。

1.1 材質與紋理的核心作用

  • 核心作用
    • 讓用戶與3D場景中的物體動態互動(如點擊按鈕、拖拽物體、觸發事件)。
    • 提升沉浸感:交互是游戲、數據可視化、虛擬展廳的核心功能。
  • 案例對比
    • 無交互:靜態場景,用戶只能被動觀察。
    • 有交互:點擊物體彈出信息、拖拽旋轉模型、射線檢測選中目標。

2. 基礎交互:鼠標與觸摸事件

2.1 綁定鼠標點擊事件

  • Babylon.js 的 ActionManager
    通過事件管理器簡化交互邏輯,支持點擊、懸停、拖拽等事件。

  • 代碼示例:點擊立方體變色

    const box = BABYLON.MeshBuilder.CreateBox("box", {}, scene);box.actionManager = new BABYLON.ActionManager(scene);// 綁定點擊事件box.actionManager.registerAction(new BABYLON.ExecuteCodeAction(BABYLON.ActionManager.OnPickTrigger, // 觸發條件:點擊() => {box.material.diffuseColor = BABYLON.Color3.Random(); // 隨機顏色}));
    

2.2 觸摸事件適配

  • 移動端兼容性
    Babylon.js 自動處理觸摸事件,無需額外代碼。

  • 示例:雙指縮放與旋轉

      camera.attachControl(canvas, true); // 啟用觸控支持camera.inputs.add(new BABYLON.FreeCameraTouchInput()); // 添加觸控輸入
    

3. 射線檢測(Ray Casting)

3.1 射線檢測的原理

  • 核心機制
    從屏幕點擊位置向3D場景發射一條射線,檢測與物體的碰撞點。

  • 代碼實現:點擊選中物體

      scene.onPointerDown = (evt, pickResult) => {if (pickResult.hit) {const hitMesh = pickResult.pickedMesh;// 高亮選中物體hitMesh.material.emissiveColor = BABYLON.Color3.Yellow();}};
    

3.2 高級射線檢測技巧

  • 篩選檢測目標
    僅檢測特定類型的物體(如可交互的按鈕)。

      const ray = new BABYLON.Ray(camera.position, scene.pointerX, scene.pointerY // 從屏幕坐標生成射線方向);const predicate = (mesh) => mesh.name.startsWith("interactive_"); // 僅檢測名稱前綴為 interactive_ 的物體const hit = scene.pickWithRay(ray, predicate);
    
  • 長按檢測與連續觸發

      let isHolding = false;scene.onPointerObservable.add((pointerInfo) => {if (pointerInfo.type === BABYLON.PointerEventTypes.POINTERDOWN) {isHolding = true;// 開始長按檢測const interval = setInterval(() => {if (!isHolding) clearInterval(interval);// 持續觸發邏輯(如充能效果)}, 100);} else if (pointerInfo.type === BABYLON.PointerEventTypes.POINTERUP) {isHolding = false;}});
    

4. 拖拽物體的實現

4.1 拖拽基礎:平面拖拽

  • 步驟分解
    1. 按下時:檢測是否選中物體,記錄初始位置。
    2. 移動時:根據鼠標位移更新物體位置。
    3. 釋放時:結束拖拽。

  • 代碼示例

      let draggedMesh = null;
    let startPosition = null;scene.onPointerDown = (evt, pickResult) => {
    if (pickResult.hit) {draggedMesh = pickResult.pickedMesh;startPosition = draggedMesh.position.clone();
    }
    };scene.onPointerMove = () => {
    if (draggedMesh) {const ray = scene.createPickingRay(scene.pointerX, scene.pointerY);const hit = scene.pickWithRay(ray);if (hit.pickedPoint) {// 在平面上拖拽(Y軸固定)draggedMesh.position.x = hit.pickedPoint.x;draggedMesh.position.z = hit.pickedPoint.z;}
    }
    };scene.onPointerUp = () => {
    draggedMesh = null;
    };
    

4.2 3D 空間自由拖拽

  • 基于射線與碰撞點
      scene.onPointerMove = () => {if (draggedMesh) {const ray = scene.createPickingRay(scene.pointerX, scene.pointerY);const hit = scene.pickWithRay(ray);if (hit.pickedPoint) {draggedMesh.position = hit.pickedPoint; // 直接移動到碰撞點}}};
    

4.3 拖拽限制(軸向鎖定、范圍限制)

  • 限制拖拽方向
      // 只允許沿 X 軸拖拽draggedMesh.position.x = hit.pickedPoint.x;draggedMesh.position.y = startPosition.y; // 固定 Y 軸draggedMesh.position.z = startPosition.z; // 固定 Z 軸
    
  • 限制拖拽范圍
      draggedMesh.position.x = Math.min(10, Math.max(-10, hit.pickedPoint.x)); // X 軸范圍 [-10, 10]
    

5. 高級交互技巧

5.1 組合交互:拖拽 + 旋轉/縮放

  • 拽時旋轉物體
  let time = 0;scene.registerBeforeRender(() => {material.diffuseColor = new BABYLON.Color3(Math.sin(time) * 0.5 + 0.5, // R通道Math.cos(time) * 0.5 + 0.5, // G通道0.5                         // B通道);time += 0.02;});

5.2 交互反饋設計

  • 懸停高亮
      mesh.actionManager.registerAction(new BABYLON.SetValueAction(BABYLON.ActionManager.OnPointerOverTrigger,mesh.material,"emissiveColor",BABYLON.Color3.White() // 懸停時發光));mesh.actionManager.registerAction(new BABYLON.SetValueAction(BABYLON.ActionManager.OnPointerOutTrigger,mesh.material,"emissiveColor",BABYLON.Color3.Black() // 恢復原色));
    

5.3 性能優化

  • 減少射線檢測頻率
      let lastCheck = 0;scene.onPointerMove = () => {if (Date.now() - lastCheck > 100) { // 每 100ms 檢測一次const hit = scene.pick(scene.pointerX, scene.pointerY);lastCheck = Date.now();}};
    
  • 使用 Octree 加速檢測
      scene.createOrUpdateSelectionOctree(); // 創建空間索引const hit = scene.pickWithRay(ray, (mesh) => true, true); // 啟用 Octree 優化
    

6. 實戰任務

任務 1:實現可拖拽的拼圖游戲

  • 目標:拖拽碎片到正確位置后自動吸附。
  • 代碼要點
      if (distanceBetween(draggedMesh.position, targetPosition) < 0.5) {draggedMesh.position = targetPosition.clone(); // 自動吸附showSuccessEffect();}
    

任務 2:射線檢測射擊游戲

  • 目標:點擊屏幕發射子彈,擊中目標后爆炸。
  • 代碼要點
      scene.onPointerDown = (evt, pickResult) => {if (pickResult.hit) {const explosion = BABYLON.MeshBuilder.CreateSphere("explosion", { diameter: 2 }, scene);explosion.position = pickResult.pickedPoint;explosion.material = new BABYLON.StandardMaterial("explodeMat", scene);explosion.material.emissiveColor = BABYLON.Color3.Red();setTimeout(() => explosion.dispose(), 500); // 0.5秒后消失}};
    

7. 常見問題與解決方案

7.1 射線檢測不準確

  • 原因:模型碰撞邊界(Bounding Box)與視覺不匹配。
  • 解決
    • 為復雜模型設置精確碰撞體
      mesh.checkCollisions = true;mesh.ellipsoid = new BABYLON.Vector3(1, 2, 1); // 自定義碰撞范圍
    

7.2 拖拽時物體穿透地面

  • 解決
    • 啟用物理引擎并添加碰撞約束:
        new BABYLON.PhysicsImpostor(mesh, BABYLON.PhysicsImpostor.BoxImpostor, {mass: 1,friction: 0.5}, scene);
    

8. 總結與下一章預告

8.1 關鍵知識點回顧

  • 件綁定、射線檢測、拖拽邏輯、交互反饋設計。
  • 擴展方向:
    • 手勢識別:捏合縮放、滑動旋轉。
    • VR 交互:通過 WebXR 實現手柄射線交互。
    • 多人協作:通過 WebSocket 同步交互狀態。

8.2 下一章預告

  • 《動畫基礎:關鍵幀動畫與緩動效果》:創建簡單動畫,使用動畫曲線(Easing Functions)優化效果。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/81781.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/81781.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/81781.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

adb抓包

目錄 抓包步驟 步驟 1: 獲取應用的包名 步驟 2: 查看單個應用的日志 步驟 3: 使用日志級別過濾器 步驟 4: 高級日志過濾 可能的原因&#xff1a; 解決方案&#xff1a; 額外提示&#xff1a; 日志保存 抓包步驟 連接設備 adb devices 步驟 1: 獲取應用的包名 首先…

什么是實時流數據?核心概念與應用場景解析

在當今數字經濟時代&#xff0c;實時流數據正成為企業核心競爭力。金融機構需要實時風控系統在欺詐交易發生的瞬間進行攔截&#xff1b;電商平臺需要根據用戶實時行為提供個性化推薦&#xff1b;工業物聯網需要監控設備狀態預防故障。這些場景都要求系統能夠“即時感知、即時分…

百度飛槳OCR(PP-OCRv4_server_det|PP-OCRv4_server_rec_doc)文本識別-Java項目實踐

什么是OCR? OCR&#xff08;Optical Character Recognition&#xff0c;光學字符識別&#xff09;是一種通過技術手段將圖像或掃描件中的文字內容轉換為可編輯、可搜索的文本格式&#xff08;如TXT、Word、PDF等&#xff09;的技術。它廣泛應用于文檔數字化、信息提取、自動化…

Pytorch實現常用代碼筆記

Pytorch實現常用代碼筆記 基礎實現代碼其他代碼示例Networks or ProjectsNetwork ModulesLossUtils 基礎實現代碼 參考 深度學習手寫代碼 其他代碼示例 Networks or Projects SENet學習筆記 SKNet——SENet孿生兄弟篇 GCNet&#xff1a;當Non-local遇見SENet YOLOv1到YOLO…

word通配符表

目錄 一、word查找欄代碼&通配符一覽表二、word替換欄代碼&通配符一覽表三、參考文獻 一、word查找欄代碼&通配符一覽表 序號清除使用通配符復選框勾選使用通配符復選框特殊字符代碼特殊字符代碼or通配符1任意單個字符^?一個任意字符?2任意數字^#任意數字&#…

TYUT-企業級開發教程-第6章

這一章 考點不多 什么是緩存&#xff1f;為什么要設計出緩存&#xff1f; 企業級應用為了避免讀取數據時受限于數據庫的訪問效率而導致整體系統性能偏低&#xff0c;通 常會在應用程序與數據庫之間建立一種臨時的數據存儲機制&#xff0c;該臨時存儲數據的區域稱 為緩存。緩存…

雙檢鎖(Double-Checked Locking)單例模式

在項目中使用雙檢鎖&#xff08;Double-Checked Locking&#xff09;單例模式來管理 JSON 格式化處理對象&#xff08;如 ObjectMapper 在 Jackson 庫中&#xff0c;或 JsonParser 在 Gson 庫中&#xff09;是一種常見的做法。這種模式確保了對象只被創建一次&#xff0c;同時在…

華為網路設備學習-22(路由器OSPF-LSA及特殊詳解)

一、基本概念 OSPF協議的基本概念 OSPF是一種內部網關協議&#xff08;IGP&#xff09;&#xff0c;主要用于在自治系統&#xff08;AS&#xff09;內部使路由器獲得遠端網絡的路由信息。OSPF是一種鏈路狀態路由協議&#xff0c;不直接傳遞路由表&#xff0c;而是通過交換鏈路…

數獨求解器3.0 增加latex格式讀取

首先說明兩種讀入格式 latex輸入格式說明 \documentclass{article} \begin{document}This is some text before oku.\begin{array}{|l|l|l|l|l|l|l|l|l|} \hline & & & & 5 & & 2 & 9 \\ \hline& & 5 & 1 & & 7…

20250520在全志H3平臺的Nano Pi NEO CORE開發板上運行Ubuntu Core16.04.3時跑通4G模塊EC20

1、h3-sd-friendlycore-xenial-4.14-armhf-20210618.img.gz 在WIN10下使用7-ZIP解壓縮/ubuntu20.04下使用tar 2、Win32DiskImager.exe 寫如32GB的TF卡。【以管理員身份運行】 3、TF卡如果已經做過會有3個磁盤分區&#xff0c;可以使用SD Card Formatter/SDCardFormatterv5_WinE…

精益數據分析(74/126):從愿景到落地的精益開發路徑——Rally的全流程管理實踐

精益數據分析&#xff08;74/126&#xff09;&#xff1a;從愿景到落地的精益開發路徑——Rally的全流程管理實踐 在創業的黏性階段&#xff0c;如何將抽象的愿景轉化為可落地的產品功能&#xff1f;如何在快速迭代中保持戰略聚焦&#xff1f;今天&#xff0c;我們通過Rally軟…

Javascript 編程基礎(4)函數 | 4.3、apply() 與 call() 方法

文章目錄 一、apply() 與 call() 方法1、核心概念1.1、call() 方法1.2、apply() 方法 2、使用示例2.1、基本用法2.2、處理 this 指向問題 3、call() 與 apply() 的區別 一、apply() 與 call() 方法 apply() 和 call() 都是 JavaScript 函數對象的方法&#xff0c;用于顯式設置函…

讀一本書第一遍是快讀還是細讀?

在時間充足且計劃對重要書籍進行多遍閱讀的前提下&#xff0c;第一遍閱讀的策略可以結合**「快讀搭建框架」與「標記重點」**&#xff0c;為后續細讀奠定基礎。以下是具體建議及操作邏輯&#xff1a; 一、第一遍&#xff1a;快讀為主&#xff0c;目標是「建立全局認知」 1. 快…

基于大模型的全面驚厥性癲癇持續狀態技術方案

目錄 一、數據收集與預處理系統1.1 多模態數據集成模塊1.2 數據預處理流程二、大模型構建與訓練系統2.1 模型架構設計2.2 訓練流程三、術前評估系統3.1 癲癇發作風險預測3.2 手術可行性評估流程四、術中決策支持系統4.1 實時監測數據處理4.2 麻醉方案優化流程五、術后護理系統5…

React 19 中的useRef得到了進一步加強。

文章目錄 前言一 useRef 的核心原理1.1 為什么需要 useRef&#xff1f;1.2 基本語法 二、React 19 中 useRef 的常見用法2.1 訪問 DOM 元素2.2 保存跨渲染的數據 三、React 19 中的改進ref 作為一個屬性案例演示(觸發子組件焦點事件) 注意 總結 前言 在 React 的世界里&#x…

idea查看class文件源碼

1、在idea中查看.class文件源碼 在idea的一個工程里面將.class文件復制進去&#xff0c;會提示如下&#xff1a; 這時候&#xff0c;打開一個其他類&#xff0c;右鍵-》"show in explorer"&#xff0c;打開資源文件夾&#xff0c;這時候將class文件粘貼在此處&#…

基于 Vue + CEF3 的瀏覽器批量管理系統(附功能詳解)

&#x1f310; 基于 Vue CEF3 的瀏覽器批量管理系統&#xff08;附功能詳解&#xff09; 在當前多任務操作需求日益增長的背景下&#xff0c;如何高效管理多個瀏覽器實例成為了一個值得探討的問題。今天給大家介紹一款基于 Vue 和 CEF3 構建的瀏覽器批量管理系統&#xff0c;…

JS實現古詩豎排從右至左

一個老題目&#xff0c;將下面古詩文由橫排&#xff0c;變成古文豎排模式&#xff1a; 靜夜思 李白 床前明月光&#xff0c; 疑似地上霜。 舉頭望明月&#xff0c; 低頭思故鄉。變成&#xff1a; 低|舉|疑|床|靜 頭|頭|似|前|夜 思|望|地|明|思 故|明|上|月| 鄉|月|霜|光|李…

在 Android 中實現支持多手勢交互的自定義 View(Kotlin 完整指南)

本文將手把手教你創建一個支持拖動、縮放、旋轉等多種手勢交互的自定義 View&#xff0c;并提供完整的代碼實現和優化建議。 一、基礎實現 1.1 創建自定義 View 骨架 import android.content.Context import android.graphics.* import android.util.AttributeSet import an…

Kotlin 協程 (一)

1. Kotlin 協程的核心概念 1.1 協程&#xff08;Coroutine&#xff09; 定義&#xff1a;協程是一種輕量級的執行上下文&#xff0c;可以在任何時候掛起和恢復&#xff0c;而不需要阻塞線程。特點&#xff1a; 比傳統線程更輕量&#xff0c;開銷更小。支持掛起和恢復&#xf…