\chapter{知识模型} \section{基本模型} 在建立数字孪生虚拟世界过程中,会有大大小小的规则、算法等知识纳入其中,任何规则算法归纳来讲都是描述任意虚拟或实体对象相关作用关系。本文归纳了这些规则、算法的共同特征,建立了一个一般性的知识模型,该模型是一个动态模型,其知识求解过程可根据特点纳入平台内运算或使用独立进程进行运算求解。 基本模型需要先建立三个外部特征,触发域、输入域、输出域。触发域主要用于设定触发求解过程的条件。输入域是指定该模型需要哪些虚拟/实体对象的什么参数。输出域是指定该模型输入影响范围和参数。 基本模型内部求解过程可以根据类型和功能特点选择提交公式或算法代码,或直接运行独立的求解程序。 \section{知识分类} 对于不同的知识或者说规则,根据其作用域和功能特点,将其分为现实类知识、虚拟类知识、仿真类知识 \subsection{现实类知识} 该类知识是具体场景下最底层知识,其触发域和输入域仅能为实体对象数据,虚拟场景运行与否不影响该类知识触发和生效作用。 \subsection{仿真类知识} 该类知识为虚拟环境中与实体对象对应的虚拟对象的数据的关联知识,其输出域可以设定于虚拟世界,也可作用于现实世界。 \subsection{虚拟类知识} 该类知识其输出域仅能作用于虚拟世界。 \section{碰撞检测} 碰撞检测目前定义为虚拟类知识,暂时其输出域数据无法作用于现实世界,主要用于虚拟世界用户交互检测。 为了简化物体之间的碰撞检测运算,通常会对物体创建一个规则的几何外形将其包围。在本系统中,碰撞检测中将物体分为三种检测模型,点、AABB、球体。其中,AABB(axis-aligned bounding box)包围盒被称为轴对齐包围盒。 轴对齐包围盒是判断两个物体是否重叠的最快算法,物体被包裹在一个非旋转的(因此轴对齐的)盒中,并检查这些盒在三维坐标空间中的位置,以确定它们是否重叠。 由于性能原因,轴对齐是有一些约束的。两个非旋转的盒子之间是否重叠可以通过逻辑比较进行检查,而旋转的盒子则需要三角运算,这会导致性能下降。如果你有旋转的物体,可以通过修改边框的尺寸,这样盒子仍可以包裹物体,或者选择使用另一种边界几何类型,比如球体 (球体旋转,形状不会变)。 \subsection{点与AABB} 如果检测到一个点是否在 AABB 内部就非常简单了 — 我们只需要检查这个点的坐标是否在 AABB 内; 分别考虑到每种坐标轴。如果假设 $P_x$, $P_y$ 和 $P_z$ 是点的坐标, $B_{minX} - B_{maxX}$, $B_{minY} - B_{maxY}$, 和$B_{minZ}–B_{maxZ}$ 是 AABB 的每一个坐标轴的范围,我们可以使用以下公式计算两者之间的碰撞是否发生: \begin{lstlisting}[ language={}, label={code-js-sample}, ] function isPointInsideAABB(point, box) { return (point.x >= box.minX && point.x <= box.maxX) && (point.y >= box.minY && point.y <= box.maxY) && (point.z >= box.minY && point.z <= box.maxZ); } \end{lstlisting} \subsection{AABB与AABB} 检查一个 AABB 是否和另一个 AABB 相交类似于检测两个点一样。我们只需要基于每一条坐标轴并利用盒子的边缘去检测。 \begin{lstlisting}[ language={}, label={code-js-sample}, ] function intersect(a, b) { return (a.minX <= b.maxX && a.maxX >= b.minX) && (a.minY <= b.maxY && a.maxY >= b.minY) && (a.minZ <= b.maxZ && a.maxZ >= b.minZ); } \end{lstlisting} \section{刚体运动力学模型} 在虚拟世界中为关联现实设备运动状态,需要根据已有的传感器数据,如加速度、里程信息等估计实体对象运动姿态,或者由虚拟对象指导影响实体对象运动,两者相互作用皆需要实现基本的刚体运动。 刚体的运动主要基于牛顿三大定律来模拟: \begin{itemize} \item 1.惯性 物体在不受力时,总是保持速度不变. \item 2.力,质量,加速度力在物体上产生加速度,满足$F = ma$. \item 3.力的作用是相互的 \end{itemize} 基于牛顿三大定律,在计算机中来模拟刚体的运动,物理引擎来模拟的流程大致都是这样的: 对于每个物体,使用循环的方式来模拟: % 流程图定义基本形状 \tikzstyle{startstop} = [rectangle, rounded corners, minimum width = 2cm, minimum height=1cm,text centered, draw = black] \tikzstyle{io} = [trapezium, trapezium left angle=70, trapezium right angle=110, minimum width=2cm, minimum height=1cm, text centered, draw=black] \tikzstyle{process} = [rectangle, minimum width=3cm, minimum height=1cm, text centered, draw=black] \tikzstyle{decision} = [diamond, aspect = 3, text centered, draw=black] % 箭头形式 \tikzstyle{arrow} = [->,>=stealth] \begin{center} \begin{tikzpicture}[node distance=0.5cm] %定义流程图具体形状 \node[startstop](start){Start}; \node[io, below of = start, yshift = -1cm](in1){分析受力}; \node[process, below of = in1, yshift = -1cm](pro1){更新速度和位置}; \node[process, below of = pro1, yshift = -1cm](pro2){碰撞检测}; \node[io, below of = pro2, yshift = -1cm](out1){解决约束}; \node[decision, below of = out1, yshift = -1cm](dec1){到达稳态}; \node[startstop, below of = dec1, yshift = -1cm](stop){显示结果}; \coordinate (point1) at (-3cm, -6cm); %连接具体形状 \draw [arrow] (start) -- (in1); \draw [arrow] (in1) -- (pro1); \draw [arrow] (pro1) -- (pro2); \draw [arrow] (pro1) -- (out1); \draw [arrow] (out1) -- (dec1); \draw (dec1) -- node [above] {N} (point1); \draw [arrow] (point1) |- (in1); \draw [arrow] (dec1) -- node [right] {Y} (stop); \end{tikzpicture} \end{center} \subsection{理想粒子的运动} 先不考虑物体的形状和旋转,把物体当成理想粒子来对待,根据牛顿定律来循环计算物体的速度和位置: \[ dt = t_{i+1} - t_{i} \] \[ v(t_{i+1}) = v(t_{i}) + (\frac{f(t_{i})}{m})dt \] \[ p(t_{i+1}) = v(t_{i}) + v(t_{i+1})dt \] 将其泰勒展开 \[ p(t_{i+1}) = p(t_{i}) + p^{'}(t_{i})dt + p^{''}(t_{i})\frac{dt^{2}}{2!} + p^{'''}(t_{i})\frac{dt^{3}}{3!} + ... \] 对于浏览器按像素点实时位置渲染精度而言,3阶泰勒展开已符合精度要求。 \subsection{3d物体旋转运动} 惯性张量 在三维空间中任取一点$Q$ 及一个直角坐标系$Q_{xyz}$,可以得到物体的惯性张量: \begin{equation} I ={ \left[ \begin{array}{ccc} I_{xx} & I_{xy} & I_{xz}\\ I_{yz} & I_{yy} & I_{yz}\\ I_{zx} & I_{zy} & I_{zz} \end{array} \right ]} \end{equation} 对角元素$I_{xx}$,$I_{yy}$,$I_{yy}$是物体分别相对于$x$,$y$,$z$轴的转动惯量。 \[ I_{xx} = \int{(r_{y}^{2}+r_z^2)dm} \] \[ I_{yy} = \int{(r_{x}^{2}+r_z^2)dm} \] \[ I_{zz} = \int{(r_{x}^{2}+r_y^2)dm} \] 计算惯量积 \[ I_{xy} = I_{yx} = - \int{(r_x r_y)dm} \] \[ I_{xz} = I_{zx} = - \int{(r_x r_z)dm} \] \[ I_{yz} = I_{zy} = - \int{(r_z r_y)dm} \] 根据惯性张量计算力矩$\tau$,角将速度$d\omega$,角速度$\omega$。 \[ \tau = \frac{dL}{dt} = I \frac{d\omega}{dt} \] \[ d\omega = I^{-1} \tau dt \] \[ \omega(t_{i+1}) = \omega(t_i) + (I^{-1} \tau(t_i)) dt \] 用四元数$q$来表示刚体的旋转状态,刚体在$dt$时间内沿着$\omega$旋转了$|\omega dt|$的角度,得到 \begin{equation} q(t_{i+1}) = q(t_i) * [\cos{\frac{|\omega dt|}{2}},\sin{\frac{|\omega dt|}{2}}\frac{\omega}{|\omega|}] \end{equation}