@realsee/five
Version:
Realsee Renderer SDK
102 lines (96 loc) • 29.4 kB
HTML
<html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>features/raycast | 如视 Five SDK</title><meta name="description" content="Documentation for 如视 Five SDK"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script><script async src="../assets/hierarchy.js" id="tsd-hierarchy-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="../index.html" class="title">如视 Five SDK</a><div id="tsd-toolbar-links"></div><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-search"></use></svg></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb" aria-label="Breadcrumb"><li><a href="" aria-current="page">features/raycast</a></li></ul></div><div class="tsd-panel tsd-typography"><h1 id="raycast-射线检测" class="tsd-anchor-link">Raycast (射线检测)<a href="#raycast-射线检测" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h1>
<ul>
<li><strong>Summary</strong>: Five 提供了增强版的射线检测机制,内置 BVH 加速,并扩展了 Three.js Raycaster 以支持更灵活的过滤和性能优化。</li>
<li><strong>Schema</strong>: 参见下方 <code>Three.js Raycaster Extensions</code>。</li>
<li><strong>Concepts</strong>: BVH, IntersectRaycaster, Raycaster Extensions。</li>
<li><strong>Examples</strong>: 提供基础检测与性能优化示例。</li>
</ul>
<h2 id="schema-threejs-raycaster-extensions" class="tsd-anchor-link">Schema: Three.js Raycaster Extensions<a href="#schema-threejs-raycaster-extensions" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2>
<blockquote>
<p><strong>Definition</strong>: <a href="../../five/declare.d.ts">Raycaster</a></p>
</blockquote>
<p>Five 对 Three.js 的 <code>Raycaster</code> 进行了扩展,在 <code>declare module 'three'</code> 中增加了以下属性:</p>
<pre><code class="typescript"><span class="hl-8">// defined in five/declare.d.ts</span><br/><span class="hl-3">declare</span><span class="hl-1"> </span><span class="hl-3">module</span><span class="hl-1"> </span><span class="hl-9">'three'</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-10">export</span><span class="hl-1"> </span><span class="hl-3">interface</span><span class="hl-1"> </span><span class="hl-7">Raycaster</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-8">/**</span><br/><span class="hl-8"> * 只捕获第一个焦点 (性能优化)</span><br/><span class="hl-8"> * - true: 找到第一个交点后立即停止检测,返回结果。</span><br/><span class="hl-8"> * - false (默认): 检测所有可能的交点。</span><br/><span class="hl-8"> */</span><br/><span class="hl-1"> </span><span class="hl-6">firstHitOnly</span><span class="hl-1">?: </span><span class="hl-7">boolean</span><span class="hl-1">;</span><br/><br/><span class="hl-1"> </span><span class="hl-8">/**</span><br/><span class="hl-8"> * 自定义交点过滤器</span><br/><span class="hl-8"> * - 回调函数,返回 boolean。</span><br/><span class="hl-8"> * - true: 保留该交点。</span><br/><span class="hl-8"> * - false: 丢弃该交点。</span><br/><span class="hl-8"> */</span><br/><span class="hl-1"> </span><span class="hl-5">hitFilter</span><span class="hl-1">?: (</span><span class="hl-6">intersect</span><span class="hl-1">: </span><span class="hl-7">THREE</span><span class="hl-1">.</span><span class="hl-7">Intersection</span><span class="hl-1">) </span><span class="hl-3">=></span><span class="hl-1"> </span><span class="hl-7">boolean</span><span class="hl-1">;</span><br/><br/><span class="hl-1"> </span><span class="hl-8">/**</span><br/><span class="hl-8"> * 是否由近及远排序</span><br/><span class="hl-8"> * - true (默认): 返回的结果数组按距离摄像机从近到远排序。</span><br/><span class="hl-8"> * - false: 结果顺序不确定(通常按遍历顺序)。</span><br/><span class="hl-8"> */</span><br/><span class="hl-1"> </span><span class="hl-6">sortByDistance</span><span class="hl-1">?: </span><span class="hl-7">boolean</span><span class="hl-1">;</span><br/><br/><span class="hl-1"> </span><span class="hl-8">/**</span><br/><span class="hl-8"> * 作用楼层 (Five 特有逻辑)</span><br/><span class="hl-8"> * - 用于多楼层场景过滤。</span><br/><span class="hl-8"> */</span><br/><span class="hl-1"> </span><span class="hl-6">floorIndex</span><span class="hl-1">?: </span><span class="hl-7">number</span><span class="hl-1">;</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-10">export</span><span class="hl-1"> </span><span class="hl-3">interface</span><span class="hl-1"> </span><span class="hl-7">Intersection</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-8">/** 命中的具体 Tile 对象 (仅 3DTiles) */</span><br/><span class="hl-1"> </span><span class="hl-6">tile</span><span class="hl-1">?: </span><span class="hl-7">Tile</span><span class="hl-1">;</span><br/><span class="hl-1"> </span><span class="hl-8">/** 命中的 ViewLayer 对象 */</span><br/><span class="hl-1"> </span><span class="hl-6">viewLayer</span><span class="hl-1">?: </span><span class="hl-7">ViewLayer</span><span class="hl-1">;</span><br/><span class="hl-1"> </span><span class="hl-8">/** 命中的 Model 对象 */</span><br/><span class="hl-1"> </span><span class="hl-6">model</span><span class="hl-1">?: </span><span class="hl-7">Model</span><span class="hl-1">;</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span>
</code><button type="button">Copy</button></pre>
<h2 id="concepts" class="tsd-anchor-link">Concepts<a href="#concepts" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2>
<h3 id="1-five-内置-bvh-bounding-volume-hierarchy" class="tsd-anchor-link">1. Five 内置 BVH (Bounding Volume Hierarchy)<a href="#1-five-内置-bvh-bounding-volume-hierarchy" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3>
<p>Five 内置了一套高效的 BVH 实现,用于优化 <code>Mesh</code> 和 <code>Points</code> 的射线检测。</p>
<ul>
<li><strong>作用</strong>: 在进行射线检测时,不直接遍历所有三角形或点,而是先与构建好的 BVH 树(包围盒层次结构)进行相交测试。只有当射线穿过包围盒时,才进一步检测内部的几何体。</li>
<li><strong>优势</strong>: 极大提升了复杂模型(如数十万面的 Mesh 或百万级 Points)的碰撞检测性能。</li>
<li><strong>透明性</strong>: 开发者通常无需手动操作 BVH,Five 在加载模型时会自动构建,并在调用 <code>intersectRaycaster</code> 时自动应用。</li>
</ul>
<h3 id="2-modelsintersectraycaster-modelintersectraycaster-vs-原生-intersectobject" class="tsd-anchor-link">2. models.intersectRaycaster / model.intersectRaycaster vs 原生 intersectObject<a href="#2-modelsintersectraycaster-modelintersectraycaster-vs-原生-intersectobject" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3>
<p>Five 提供了 <code>model.intersectRaycaster</code> 方法,与 Three.js 原生的 <code>raycaster.intersectObject</code> 有显著区别:</p>
<table>
<thead>
<tr>
<th style="text-align:left">特性</th>
<th style="text-align:left"><code>five.model.intersectRaycaster</code></th>
<th style="text-align:left"><code>raycaster.intersectObject</code> (Three.js 原生)</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><strong>检测范围</strong></td>
<td style="text-align:left">聚合检测 <code>five.model.shownModels</code> 中所有可见模型。</td>
<td style="text-align:left">仅检测指定的单个 Object3D 及其子节点。</td>
</tr>
<tr>
<td style="text-align:left"><strong>结果排序</strong></td>
<td style="text-align:left">自动合并所有模型的检测结果,并根据 <code>raycaster.sortByDistance</code> 排序。</td>
<td style="text-align:left">仅对当前 Object 及其子节点的结果排序。</td>
</tr>
<tr>
<td style="text-align:left"><strong>扩展支持</strong></td>
<td style="text-align:left"><strong>支持</strong> <code>firstHitOnly</code>, <code>hitFilter</code>, <code>sortByDistance</code> 等扩展属性。</td>
<td style="text-align:left">不支持 Five 的扩展属性(需手动实现)。</td>
</tr>
<tr>
<td style="text-align:left"><strong>内部优化</strong></td>
<td style="text-align:left">自动调用模型内部的优化逻辑(如 BVH, Tile3D 的空间索引)。</td>
<td style="text-align:left">仅进行标准的场景图遍历检测。</td>
</tr>
<tr>
<td style="text-align:left"><strong>使用场景</strong></td>
<td style="text-align:left"><strong>推荐</strong>。适用于全局点击、地板检测、物体拾取等业务场景。</td>
<td style="text-align:left">仅在需要检测特定原生 Object3D 时使用。</td>
</tr>
</tbody>
</table>
<h2 id="examples" class="tsd-anchor-link">Examples<a href="#examples" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2>
<h3 id="基础用法:检测点击位置" class="tsd-anchor-link">基础用法:检测点击位置<a href="#基础用法:检测点击位置" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3>
<p>最常见的场景是将鼠标点击的屏幕坐标转换为 3D 空间中的点。</p>
<pre><code class="typescript"><span class="hl-10">import</span><span class="hl-1"> </span><span class="hl-3">*</span><span class="hl-1"> </span><span class="hl-10">as</span><span class="hl-1"> </span><span class="hl-6">THREE</span><span class="hl-1"> </span><span class="hl-10">from</span><span class="hl-1"> </span><span class="hl-9">'three'</span><span class="hl-1">;</span><br/><span class="hl-10">import</span><span class="hl-1"> { </span><span class="hl-6">Five</span><span class="hl-1"> } </span><span class="hl-10">from</span><span class="hl-1"> </span><span class="hl-9">'@realsee/five'</span><span class="hl-1">;</span><br/><br/><span class="hl-3">const</span><span class="hl-1"> </span><span class="hl-4">five</span><span class="hl-1"> = </span><span class="hl-3">new</span><span class="hl-1"> </span><span class="hl-5">Five</span><span class="hl-1">();</span><br/><span class="hl-8">// ... 初始化 ...</span><br/><br/><span class="hl-3">const</span><span class="hl-1"> </span><span class="hl-4">raycaster</span><span class="hl-1"> = </span><span class="hl-3">new</span><span class="hl-1"> </span><span class="hl-4">THREE</span><span class="hl-1">.</span><span class="hl-5">Raycaster</span><span class="hl-1">();</span><br/><span class="hl-3">const</span><span class="hl-1"> </span><span class="hl-4">vector</span><span class="hl-1"> = </span><span class="hl-3">new</span><span class="hl-1"> </span><span class="hl-4">THREE</span><span class="hl-1">.</span><span class="hl-5">Vector2</span><span class="hl-1">();</span><br/><br/><span class="hl-8">// 假设 onTap 是点击事件处理函数</span><br/><span class="hl-3">function</span><span class="hl-1"> </span><span class="hl-5">onTap</span><span class="hl-1">(</span><span class="hl-6">event</span><span class="hl-1">: { </span><span class="hl-6">x</span><span class="hl-1">: </span><span class="hl-7">number</span><span class="hl-1">, </span><span class="hl-6">y</span><span class="hl-1">: </span><span class="hl-7">number</span><span class="hl-1"> }) {</span><br/><span class="hl-1"> </span><span class="hl-8">// 1. 将屏幕坐标转换为归一化设备坐标 (NDC)</span><br/><span class="hl-1"> </span><span class="hl-8">// 注意:five.getElement() 获取 canvas 容器</span><br/><span class="hl-1"> </span><span class="hl-3">const</span><span class="hl-1"> </span><span class="hl-4">element</span><span class="hl-1"> = </span><span class="hl-6">five</span><span class="hl-1">.</span><span class="hl-5">getElement</span><span class="hl-1">();</span><br/><span class="hl-1"> </span><span class="hl-10">if</span><span class="hl-1"> (!</span><span class="hl-6">element</span><span class="hl-1">) </span><span class="hl-10">return</span><span class="hl-1">;</span><br/><br/><span class="hl-1"> </span><span class="hl-3">const</span><span class="hl-1"> </span><span class="hl-4">rect</span><span class="hl-1"> = </span><span class="hl-6">element</span><span class="hl-1">.</span><span class="hl-5">getBoundingClientRect</span><span class="hl-1">();</span><br/><span class="hl-1"> </span><span class="hl-6">vector</span><span class="hl-1">.</span><span class="hl-6">x</span><span class="hl-1"> = ((</span><span class="hl-6">event</span><span class="hl-1">.</span><span class="hl-6">x</span><span class="hl-1"> - </span><span class="hl-6">rect</span><span class="hl-1">.</span><span class="hl-6">left</span><span class="hl-1">) / </span><span class="hl-6">rect</span><span class="hl-1">.</span><span class="hl-6">width</span><span class="hl-1">) * </span><span class="hl-11">2</span><span class="hl-1"> - </span><span class="hl-11">1</span><span class="hl-1">;</span><br/><span class="hl-1"> </span><span class="hl-6">vector</span><span class="hl-1">.</span><span class="hl-6">y</span><span class="hl-1"> = -((</span><span class="hl-6">event</span><span class="hl-1">.</span><span class="hl-6">y</span><span class="hl-1"> - </span><span class="hl-6">rect</span><span class="hl-1">.</span><span class="hl-6">top</span><span class="hl-1">) / </span><span class="hl-6">rect</span><span class="hl-1">.</span><span class="hl-6">height</span><span class="hl-1">) * </span><span class="hl-11">2</span><span class="hl-1"> + </span><span class="hl-11">1</span><span class="hl-1">;</span><br/><br/><span class="hl-1"> </span><span class="hl-8">// 2. 设置射线</span><br/><span class="hl-1"> </span><span class="hl-6">raycaster</span><span class="hl-1">.</span><span class="hl-5">setFromCamera</span><span class="hl-1">(</span><span class="hl-6">vector</span><span class="hl-1">, </span><span class="hl-6">five</span><span class="hl-1">.</span><span class="hl-6">camera</span><span class="hl-1">);</span><br/><br/><span class="hl-1"> </span><span class="hl-8">// 3. 调用 Five 的检测方法</span><br/><span class="hl-1"> </span><span class="hl-3">const</span><span class="hl-1"> </span><span class="hl-4">intersects</span><span class="hl-1"> = </span><span class="hl-6">five</span><span class="hl-1">.</span><span class="hl-6">model</span><span class="hl-1">.</span><span class="hl-5">intersectRaycaster</span><span class="hl-1">(</span><span class="hl-6">raycaster</span><span class="hl-1">);</span><br/><br/><span class="hl-1"> </span><span class="hl-10">if</span><span class="hl-1"> (</span><span class="hl-6">intersects</span><span class="hl-1">.</span><span class="hl-6">length</span><span class="hl-1"> > </span><span class="hl-11">0</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-3">const</span><span class="hl-1"> </span><span class="hl-4">firstHit</span><span class="hl-1"> = </span><span class="hl-6">intersects</span><span class="hl-1">[</span><span class="hl-11">0</span><span class="hl-1">];</span><br/><span class="hl-1"> </span><span class="hl-6">console</span><span class="hl-1">.</span><span class="hl-5">log</span><span class="hl-1">(</span><span class="hl-9">'点击到了模型:'</span><span class="hl-1">, </span><span class="hl-6">firstHit</span><span class="hl-1">.</span><span class="hl-6">object</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-6">console</span><span class="hl-1">.</span><span class="hl-5">log</span><span class="hl-1">(</span><span class="hl-9">'交点坐标 (世界坐标):'</span><span class="hl-1">, </span><span class="hl-6">firstHit</span><span class="hl-1">.</span><span class="hl-6">point</span><span class="hl-1">);</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span>
</code><button type="button">Copy</button></pre>
<h3 id="性能优化:只获取第一个交点" class="tsd-anchor-link">性能优化:只获取第一个交点<a href="#性能优化:只获取第一个交点" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3>
<p>在进行如“地面检测”或“视线遮挡检测”时,通常只需要知道最近的交点。此时开启 <code>firstHitOnly</code> 可以显著提升性能。</p>
<pre><code class="typescript"><span class="hl-3">const</span><span class="hl-1"> </span><span class="hl-4">raycaster</span><span class="hl-1"> = </span><span class="hl-3">new</span><span class="hl-1"> </span><span class="hl-4">THREE</span><span class="hl-1">.</span><span class="hl-5">Raycaster</span><span class="hl-1">();</span><br/><span class="hl-6">raycaster</span><span class="hl-1">.</span><span class="hl-5">setFromCamera</span><span class="hl-1">(</span><span class="hl-6">mouseVector</span><span class="hl-1">, </span><span class="hl-6">five</span><span class="hl-1">.</span><span class="hl-6">camera</span><span class="hl-1">);</span><br/><br/><span class="hl-8">// 开启性能优化:找到最近的一个交点后立即停止</span><br/><span class="hl-6">raycaster</span><span class="hl-1">.</span><span class="hl-6">firstHitOnly</span><span class="hl-1"> = </span><span class="hl-3">true</span><span class="hl-1">;</span><br/><br/><span class="hl-8">// 结果数组长度最多为 1</span><br/><span class="hl-3">const</span><span class="hl-1"> </span><span class="hl-4">intersects</span><span class="hl-1"> = </span><span class="hl-6">five</span><span class="hl-1">.</span><span class="hl-6">model</span><span class="hl-1">.</span><span class="hl-5">intersectRaycaster</span><span class="hl-1">(</span><span class="hl-6">raycaster</span><span class="hl-1">);</span><br/><br/><span class="hl-10">if</span><span class="hl-1"> (</span><span class="hl-6">intersects</span><span class="hl-1">.</span><span class="hl-6">length</span><span class="hl-1"> > </span><span class="hl-11">0</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-8">// 处理最近的交点</span><br/><span class="hl-1">}</span>
</code><button type="button">Copy</button></pre>
<h3 id="高级用法:使用过滤器" class="tsd-anchor-link">高级用法:使用过滤器<a href="#高级用法:使用过滤器" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3>
<p>如果你只想检测特定类型的物体(例如只检测地板,忽略天花板),可以使用 <code>hitFilter</code>。</p>
<pre><code class="typescript"><span class="hl-6">raycaster</span><span class="hl-1">.</span><span class="hl-5">hitFilter</span><span class="hl-1"> = (</span><span class="hl-6">intersect</span><span class="hl-1">) </span><span class="hl-3">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-8">// 示例:假设地板的法线是向上的 (0, 1, 0)</span><br/><span class="hl-1"> </span><span class="hl-8">// 只保留法线朝上的交点(地板)</span><br/><span class="hl-1"> </span><span class="hl-10">if</span><span class="hl-1"> (</span><span class="hl-6">intersect</span><span class="hl-1">.</span><span class="hl-6">face</span><span class="hl-1"> && </span><span class="hl-6">intersect</span><span class="hl-1">.</span><span class="hl-6">face</span><span class="hl-1">.</span><span class="hl-6">normal</span><span class="hl-1">.</span><span class="hl-6">y</span><span class="hl-1"> > </span><span class="hl-11">0.5</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-10">return</span><span class="hl-1"> </span><span class="hl-3">true</span><span class="hl-1">; </span><span class="hl-8">// 保留</span><br/><span class="hl-1"> }</span><br/><span class="hl-1"> </span><span class="hl-10">return</span><span class="hl-1"> </span><span class="hl-3">false</span><span class="hl-1">; </span><span class="hl-8">// 丢弃</span><br/><span class="hl-1">};</span><br/><br/><span class="hl-3">const</span><span class="hl-1"> </span><span class="hl-4">intersects</span><span class="hl-1"> = </span><span class="hl-6">five</span><span class="hl-1">.</span><span class="hl-6">model</span><span class="hl-1">.</span><span class="hl-5">intersectRaycaster</span><span class="hl-1">(</span><span class="hl-6">raycaster</span><span class="hl-1">);</span>
</code><button type="button">Copy</button></pre>
<h2 id="debugging" class="tsd-anchor-link">Debugging<a href="#debugging" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2>
<ul>
<li><strong>验证交点</strong>: 在开发阶段,可以在交点处添加一个临时的红色小球 <code>THREE.Mesh</code>,直观地确认检测位置是否正确。</li>
<li><strong>检查模型可见性</strong>: <code>intersectRaycaster</code> 只会检测 <code>visible = true</code> 的模型。如果检测不到,请检查模型的可见性状态。</li>
<li><strong>Performance</strong>: 如果射线检测导致掉帧,检查是否频繁调用了全场景检测。尝试使用 <code>firstHitOnly</code> 或减小检测频率(如节流)。</li>
</ul>
<h2 id="common-pitfalls" class="tsd-anchor-link">Common Pitfalls<a href="#common-pitfalls" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2>
<ol>
<li><strong>混淆 API</strong>: 错误地使用 <code>raycaster.intersectObject(five.scene)</code>。虽然这也能工作,但会失去 Five 的 BVH 优化和多模型聚合能力,导致性能下降或漏检。请始终优先使用 <code>five.model.intersectRaycaster(raycaster)</code>。</li>
<li><strong>忽略坐标系</strong>: <code>raycaster.setFromCamera</code> 需要 NDC 坐标(-1 到 1),而不是像素坐标。务必进行正确的坐标转换。</li>
<li><strong>Tile3D 模型的特殊性</strong>: 对于大型 Tile3D 场景,射线检测可能涉及动态加载的瓦片。Five 内部已处理这些逻辑,外部调用方式不变,但返回的 <code>object</code> 可能是某个具体的 Tile 节点。</li>
</ol>
<h2 id="related" class="tsd-anchor-link">Related<a href="#related" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2>
<ul>
<li><a href="features_parameter.html">Parameter</a>: 了解模型参数配置。</li>
<li><a href="features_screen-project.html">Screen Project</a>: 屏幕坐标与空间坐标转换(标签、拾取的前置步骤)。</li>
<li><a href="features_event.html">Event</a>: 手势事件系统,获取点击坐标的来源。</li>
<li><a href="features_coordinate-system.html">Coordinate System</a>: 坐标系定义,理解 NDC 与世界坐标。</li>
</ul>
<hr>
<pre><code class="yaml"><span class="hl-0">tags</span><span class="hl-1">: [</span><span class="hl-2">点击</span><span class="hl-1">, </span><span class="hl-2">拾取</span><span class="hl-1">, </span><span class="hl-2">碰撞检测</span><span class="hl-1">, </span><span class="hl-2">物体选择</span><span class="hl-1">, </span><span class="hl-2">raycast</span><span class="hl-1">, </span><span class="hl-2">bvh</span><span class="hl-1">, </span><span class="hl-2">interaction</span><span class="hl-1">, </span><span class="hl-2">performance</span><span class="hl-1">, </span><span class="hl-2">picking</span><span class="hl-1">, </span><span class="hl-2">hit-test</span><span class="hl-1">, </span><span class="hl-2">click</span><span class="hl-1">, </span><span class="hl-2">floor-detection</span><span class="hl-1">]</span>
</code><button type="button">Copy</button></pre>
</div></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div><details open class="tsd-accordion tsd-page-navigation"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>On This Page</h3></summary><div class="tsd-accordion-details"><a href="#raycast-射线检测"><span>Raycast (射线检测)</span></a><ul><li><a href="#schema-threejs-raycaster-extensions"><span>Schema: <wbr/>Three.js <wbr/>Raycaster <wbr/>Extensions</span></a></li><li><a href="#concepts"><span>Concepts</span></a></li><li><ul><li><a href="#1-five-内置-bvh-bounding-volume-hierarchy"><span>1. <wbr/>Five 内置 <wbr/>BVH (<wbr/>Bounding <wbr/>Volume <wbr/>Hierarchy)</span></a></li><li><a href="#2-modelsintersectraycaster-modelintersectraycaster-vs-原生-intersectobject"><span>2. models.intersect<wbr/>Raycaster / model.intersect<wbr/>Raycaster vs 原生 intersect<wbr/>Object</span></a></li></ul></li><li><a href="#examples"><span>Examples</span></a></li><li><ul><li><a href="#基础用法:检测点击位置"><span>基础用法:检测点击位置</span></a></li><li><a href="#性能优化:只获取第一个交点"><span>性能优化:只获取第一个交点</span></a></li><li><a href="#高级用法:使用过滤器"><span>高级用法:使用过滤器</span></a></li></ul></li><li><a href="#debugging"><span>Debugging</span></a></li><li><a href="#common-pitfalls"><span>Common <wbr/>Pitfalls</span></a></li><li><a href="#related"><span>Related</span></a></li></ul></div></details></div><div class="site-menu"><nav class="tsd-navigation"><a href="../modules.html">如视 Five SDK</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>