转自微信
https://mp.weixin.qq.com/s/gqJ6vLEhGIyhVaFW8POpXw
本文根据虚幻4.21版本的文档翻译。(原文地址:https://docs.unrealengine.com/en-us/Engine/Rendering/Rendering-to-Multiple-Displays-with-nDisplay)
越来越多的可视化系统通过多个显示器来渲染实时内容,从而更有效地使用户沉浸在虚拟环境中。这些系统可以由多个相邻的物理屏幕组成,如巨幕(Powerwall), 或者使用多个投影仪将3D环境投影到物理表面上如圆顶、墙面或曲幕,例如Cave环境。
虚幻引擎通过名为nDisplay的系统支持这些应用场景。该系统解决了以下问题:
1. 简化了在网络中的不同计算机上部署和启动项目的多个实例的过程,每个实例都输出给一个或多个显示设备。
2. 根据显示硬件的空间布局,管理每个屏幕的视锥体所涉及的所有计算。
3. 确保在各个屏幕上显示的内容保持同步。
4. 提供被动和主动立体渲染。
5. 可以由来自VR追踪系统/VRPN设备的输入进行驱动,使得显示器中的视点准确地遵循现实中观看者的视点移动。
6. 可以支持任何方向的任意数量的屏幕,并且可以在任意数量的项目中轻松重复使用。
一、n显示系统概述
每个nDisplay配置都有一台主计算机和任意数量的其他计算机。
网络中的每台计算机都运行项目的打包可执行文件的一个或多个实例。每个虚幻引擎实例负责将同一3D场景的单个片段渲染到单个屏幕或显示器。
主节点还负责接受来自VRPN设备的输入,并将该输入复制到所有其他连接的计算机。
为了实现这些,nDisplay为普通的虚幻系统架构添加了几个组件:
1. 网络配置和管理应用程序,称为nDisplayLauncher 。您可以在网络中的单台计算机上运行此应用程序,以在网络中的所有计算机上自动部署和启动项目。
2. 一个名为nDisplayListener的独立侦听器应用程序,在每台计算机上运行。此应用程序侦听来自nDisplayLauncher的传入请求,并在本地计算机上处理这些请求。
3. 一个共享配置文件,包含了nDisplay需要在正确的计算机上启动正确数量实例的所有设置,每个设置为3D世界呈现正确的视点,以产生跨所有显示屏或投影仪的无缝渲染的错觉。请参阅下面的关于nDisplay配置文件。
二、入门
本节介绍如何首次启动和运行nDisplay。在开始之前:
1. 确保物理设备( 屏幕、投影仪等) 都设置好且能正常工作。
2. 确保要在主计算机上使用的Windows帐户对要在nDisplay网络中使用的所有计算机具有管理权限。
3. 确保要在nDisplay网络中使用的所有计算机都可以通过端口41000,41001和41002接收TCP/IP通信。(可以使用不同的端口。参阅下面的“更改通信端口”。)
步骤1. 为nDisplay设置项目
将项目设置为使用nDisplay的最简单方法是从nDisplay模板项目创建它:
这会自动启用nDisplay插件,并将一些示例配置文件添加到项目中,同时提供已使用默认设置的默认关卡。
如果有现有项目需要与nDisplay一起使用,则可以手动执行相同的配置。请参阅下面的“添加nDisplay到现有项目”。
步骤2.设置配置文件
需要告诉nDisplay以下信息:要在网络中使用的不同计算机、这些计算机将渲染的屏幕或投影仪的大小和分辨率、这些屏幕在关卡的3D空间中的空间关系等等。为此,需要创建一个配置文件,在该文件中通过一系列设置来表示这些信息。
创建此配置文件可能是nDisplay设置中最棘手的部分,因此要小心处理。详细信息请参阅下面的“关于nDisplay配置文件”。
通常,一旦设置了配置文件,则只需在网络拓扑发生更改时进行修改。例如,当需要更改渲染的计算机时,或者更改了屏幕的物理排列时。
将配置文件保存在Project的Content文件夹中。下一步中将使用它。
第3步。打包和部署
每次更改了项目中的内容时,都需要打包项目并将其部署到配置文件中标识的所有计算机上。
1. 打包项目。随后,当你将应用程序部署到从属计算机时,nDisplay会将其复制到每台目标计算机上的相同位置。因此,最好是先将项目打包到所有计算机上相同的位置。
2. 在虚幻引擎安装文件夹下 找到Engine\Binaries\DotNET\nDisplayListener.exe应用程序。将此应用程序复制到打包的.exe文件所在文件夹。
3. 将nDisplay配置文件复制到同一文件夹。应将打包的Project.exe文件、nDisplayListener.exe应用程序和配置文件并排放 在同一文件夹中。
4. 在虚幻引擎安装文件夹下运行Engine\Binaries\DotNET\nDisplayLauncher.exe应用程序。
5. 将已打包的Project.exe文件添加到“Application”列表中。
6. 单击“Config Files”控件右侧的“ Add”,然后浏览并选择配置文件。
7. 单击“Deploy application”。nDisplay会将项目可执行文件所在文件夹的全部内容复制到配置文件中标识的每台其他计算机上的相同位置。
步骤4.启动所有节点
将项目成功部署到配置文件中标识的所有计算机后,可以使用nDisplayLauncher应用程序同时在所有计算机上启动项目。
1. 如果尚未运行nDisplayLauncher应用程序,请启动它并按照上一节中的说明设置应用程序和配置文件。
2. 单击“ Start listeners”,将在nDisplay配置文件中标识的每台计算机上运行nDisplayListener应用程序。
3. 当nDisplay确认已在所有计算机上启动所有侦听器时,单击“Run”以启动所有实例。
完成后:
1. 单击“Kill”以在所有计算机上自动关闭虚幻引擎的所有实例,或者只关闭主计算机上运行的虚幻引擎实例。
2. 单击“Stop listeners”以关闭所有计算机上的nDisplayListener应用程序。
三、关于nDisplay配置文件
理解并创建自己的nDisplay配置文件最佳方法是从nDisplay插件提供的示例配置开始。如果已从nDisplay模板创建了项目,则可以在Project/ConfigExamples下的Project文件夹中找到这些文件。如果没有,则可以在模板/TP_nDisplayBP/Content/ConfigExamples下的虚幻引擎安装文件夹中找到这些文件。
nDisplay配置文件的结构与用于呈现可视化的不同类型组件相关联。
1. 每种组件在文件中都有自己的行, 并由指定的字符串ID标识。可以在一个配置部分需要引用另一个配置部分时使用这些字符串ID 。
2. 在此文件中配置的许多组件都在虚拟3D空间中定义了位置(以及旋转)。每个对象的位置和旋转都是相对于该对象的父级。默认情况下,所有对象的父级是VR空间原点:VR空间被启动的一个3D世界空间中的任意点。还可以在3D空间中配置特定命名的变换(Transform),称为scene_nodes,它可以充当一个或多个组件的父变换。这有助于简化屏幕,相机和其他组件的空间布局。
3. 除非另有说明,否则所有参数均以米和度为单位。
三.1 相机配置
nDisplay每次从单个视点渲染场景。这些潜在视点中的每一个都由相机配置线定义。
可以在运行时在这些视点之间切换。每个视点也可以由追踪设备驱动。
配置示例:
[camera] id=camera_static loc="X=0.Y=0,Z=1.7" tracker_id=VRPNTracking tracker_ch=0
参数 描述
id 此摄像机配置的唯一名称。
loc 此相机在VR空间中相对于其父级的位置。
tracker_id 输入配置的名称,用于定义要随时间驱动相机位置的VR设备。可选的。如果省略此参数,摄像机的位置将在VR空间中保持静态。
tracker_ch 当提供tracker_id时,此参数指定nDisplay将从中读取追踪数据的设备的频道。
parent 要作为此对象的父级的scene_node配置的名称。此参数是可选的。如果指定父级,则在loc参数中设置的值将相对于该父级。如果省略父项,则在loc参数中设置的值将相对于VR根目录。
三.2 屏幕配置
每个输出显示都使用平截椎体从当前相机位置渲染场景,平截椎体由具有大小和位置的矩形定义。这些矩形由屏幕配置定义。通常这些投影屏幕在VR空间中都具有与物理屏幕相同的尺寸。
屏幕的枢轴点始终位于其精确的中点。
配置示例:
该定义描述了一个3米乘3米的屏幕,直接位于其父节点前面。由于屏幕的枢轴点位于尺寸参数定义的矩形中心,因此我们在Z轴上添加1.5米的偏移量,将屏幕向上移动一半高度。
[screen] id=screen_front loc="X=1.5,Y=0,Z=1.5" rot="P=0,Y=0,R=0" size="X=3,Y=3" parent=screens
要在查看器的左侧定义屏幕,我们将其向左移动(Y轴上的负值),并围绕其局部Y轴(偏航)旋转,
[screen] id=screen_left loc="X=0,y=-1.5,Z=1.5" rot="P=0,Y=-90,R=0" size="X=3,Y=3" parent=screens
参数 描述
id 此屏幕配置的唯一名称。
loc 此屏幕中心在VR空间中相对于其父级的位置。
rot 屏幕面向方向的俯仰pitch(P),偏航yaw(Y)和滚动roll(R)角度,以度为单位。
size 屏幕矩形沿其局部X和Y轴的总大小(以米为单位)。
parent 要作为此对象的父级的scene_node配置的名称。此参数是可选的。如果指定父级,则在loc和rot参数中设置的值将相对于该父级。如果省略父级,则在loc和rot参数中设置的值将相对于VR根。
三.3 群集节点配置
上面定义的每个投影屏幕由应用程序的不同实例呈现。对于每个实例,需要定义cluster_node配置。每个群集节点都将引用它的投影屏幕配置。
cluster_node配置还定义了运行应用程序实例的计算机主机名或IP地址。可以为每个cluster_node配置设置不同的物理计算机,也可以在同一主机上运行多个cluster_node配置。
配置示例:
此示例配置主节点(每个网络一个):
[cluster_node] id=node_front addr=192.168.0.1 screen=screen_front viewport=vp_front sound=true port_cs=41001 port_ss=41002 master=true
此示例显示了非主集群节点:
[cluster_node] id=node_left addr=192.168.0.2 screen=screen_left viewport=vp sound=false
参数 描述
id 此集群节点配置的唯一名称。
addr 将运行此虚幻引擎实例的计算机的IP地址。必须是IPv4地址,不支持IPv6。
screen 屏幕配置的名称,用于定义此实例负责渲染的投影屏幕。
viewport 视口配置的名称,用于定义此实例运行的应用程序窗口中呈现帧的位置(参见三.4节)。
sound 确定此实例是否播放声音。可选的; 默认值是false。
Winx WinY 指定桌面上应用程序窗口左上角的位置(以屏幕空间为单位)。
ResX ResY 指定应用程序窗口的大小(以像素为单位)。确保用于此群集节点的视口定义不超过此窗口的大小。
port_cs port_ss 用于主节点与其他节点通信的集群同步端口。可选的; 默认值是14001和14002。
master 确定此实例是否为集群的主节点。只有一个cluster_node节可以将此参数设置为true。 可选的; 默认值是 false。
eye_swap 确定是否交换为左眼和右眼生成的图像。可选的。默认值是false。
三.4 视口配置
上述每个cluster_node配置里都有一个视口配置,其定义了渲染帧被映射的窗口的矩形区域。
对于每个具有不同分辨率设置的显示设备,通常需要不同的视口配置。如果所有显示屏幕都相同,则只需要一个视口配置,可以从所有集群节点配置中参考该配置。
通常,视口从应用程序窗口的左上角开始,其宽度和高度被设置以填充父窗口。但在某些情况下,可能需要在其父应用程序窗口中偏移视口。例如,如果需要设置两个部分重叠的投影仪,则可能需要执行此操作。
配置示例:
[viewport] id=vp_left X=0 Y=0 width=1920 height=1080
参数 描述
id 此视口配置的唯一名称。
X,Y 视口左上角的坐标,以像素为单位,位于主应用程序窗口的屏幕空间内。
width,height 渲染帧的宽度和高度(以像素为单位)。不应该大于使用此视口的任何cluster_node配置的size参数对应窗口的大小。
三.5 场景节点配置
在配置文件中可以定义场景节点的层次结构,每个场景节点表示3D空间中的变换。在配置文件中的需要在3D空间中进行位置和旋转的任何内容(例如相机或投影屏幕)都可以使用一个scene_node配置作为其父级。这可以帮助定义所有不同组件之间的空间关系。
与相机一样,场景节点也可以由VR追踪设备驱动。
配置示例:
下面定义了两个节点的层次结构,其中子节点在其父节点前面具有2米的偏移量。
[scene_node] id=vr_space_root loc="X=0.Y=0,Z=0" rot="P=0,Y=0,R=0"
[scene_node] id=walls_front_group loc="X=2.Y=0,Z=0" rot="P=0,Y=0,R=0" parent= vr_space_root
下行则显示了由VR跟踪设备驱动的场景节点:
[scene_node] id=cave_wand loc="X=0, Y=0,Z=1" tracker_id=CaveTracking tracker_ch=1
参数 描述
id 此场景节点配置的唯一名称。
loc 此场景节点在VR空间中相对于其父节点的位置。
rot 场景节点面向方向的俯仰(P),偏航(Y)和滚动(R)角度,以度为单位。
parent 要充当此场景节点的父节点的另一个scene_node配置的名称。此参数是可选的。如果指定父级,则在loc和rot参数中设置的值将相对于该父级。如果省略父级,则在loc和rot参数中设置的值将相对于VR根。
tracker_id 输入配置的名称,用于定义要在一段时间内驱动场景节点位置的VR设备。可选的。如果省略此参数,则场景节点的位置和旋转在VR空间中将相对于其父节点是静态的。
tracker_ch 当您提供tracker_id时,此参数指定nDisplay将从中读取追踪数据的设备的频道。
三.6 输入配置
每个摄像机和每个scene_node可以由VR跟踪设备驱动。为此,您可以为每个VR设备定义输入部分,并在摄像机或scene_node配置中引用它。
配置示例:
[input] id=CaveTracking type=tracker [email protected] loc="X=-1.5,Y=0,Z=3.4" rot="P-0,Y=0,R=0" front=X right=Y up=-Z
参数 描述
id 此输入设备配置的唯一名称。
type 此VRPN输入设备的类型:
tracker 用于追踪设备。
analog 对于生成轴数据的设备。
button 对于生成布尔按钮数据的设备。
addr 处理此特定设备的VRPN服务器的地址。该值必须符合以下格式:DEVICENAME@SERVER_ADDRESS。其中:
DEVICENAME 是此设备的VRPN名称。
SERVER_ADDRESS 是VRPN服务器的IPv4地址。
remap 此参数重新映射来自追踪设备的通道编号,以便可以从不同通道读取其输入。例如,一些控制器使用通道0进行磁头跟踪,将通道1用于控制器; 其他人使用通道1作为头部,使用通道5作为控制器。在这两个设备之间切换可能需要您更改配置和运行时代码以进行匹配。为避免在这种情况下进行任何其他更改,您可以使用此参数重新映射通道。
例如,值:
remap[0:1, 5:2]
将数据从追踪设备中的通道1转发到虚幻引擎中的通道0,并将数据从追踪设备中的通道2转发到虚幻引擎中的通道5。
设备type=tracker还接受以下附加参数:
参数 描述
rot 与其他配置部分类似,loc和rot参数指定此输入设备的局部空间中的位置和旋转偏移。但对于输入设备,通常使用这些偏移来调整VR空间中追踪设备的根位置,以匹配它在场景节点层次结构中的期望位置。
front,right,up 这些参数将追踪器的每个局部轴(前,右和上)与追踪器坐标系中的相应轴匹配。Unreal使用右手的Z-up坐标系。如果追踪器使用不同的坐标系,则可以使用这些参数将追踪器的坐标系映射到Unreal。
例如,下行将追踪器的Y轴映射到Unreal中的前(X)轴; Unreal中追踪器的X轴到右(Y)轴,Unreal中追踪器的负Z轴到向上(Z)轴:
front=Y right=X up=-Z
三.7 一般配置
一般配置包含控制nDisplay的整体操作的参数。
配置示例:
[general] swap_sync_policy=1
参数 描述
swap_sync_policy 确定输出在网络上的同步方式。
0:没有同步。
1:软件交换同步
2:NV交换锁(仅适用于使用OpenGL渲染的NVIDIA卡)
三.8 立体配置
该立体配置行设置了立体视觉(stereoscopic)的可选全局参数。
配置示例:
[stereo] eye_dist=0.064
参数 描述
eye_dist 用于为左眼和右眼生成偏移图像的眼间距离,以米为单位。
三.9 结构体
上述不同配置类型之间的引用可表示为以下结构,其中红色箭头是必要引用,绿色箭头是可选引用:
三.10 示例
举一个具体的例子。打开Content\ExampleConfigs文件夹中的wall_flat_3x2.cfg示例文件,该文件定义了六个投影屏幕,每个投影屏幕由一个单独的物理计算机渲染。
它还定义了几个scene_nodes,它们一起创建了以下层次结构:
该层次中的节点相对位置和旋转布置了相机和VR空间中的六个屏幕,使得六个投影屏幕并排,距离相机1米的距离。
注意,该配置意味着在每对相邻投影屏幕之间存在小空间,以考虑渲染场景的监视器的边缘。
四、蓝图API
您可以使用蓝图API在运行逻辑中控制nDisplay系统的行为。
要获取此API中公开的函数以管理集群,输入和呈现:
1. 在Blueprint中创建一个新的Display Cluster> Get Plugin API节点。
2. 从Out API引脚拖动,并查看Display Cluster类别:
五、Actor复制
nDisplay系统的所有输入仅由主节点处理。如果没有任何复制,只有主节点会看到场景中的更改。因此,主节点需要能够将更改复制到nDisplay网络的所有其他部分。
为此,nDisplay提供了两种可以附加到Actors的不同组件:
1. DisplayClusterSceneComponentSyncParent组件跟踪它父组件3D变换的改变,并将这些改变应用到网络中的其他集群节点。
nDisplay系统的默认DisplayClusterPawn使用了该Component 。
2. DisplayClusterSceneComponentSyncParent 组件跟踪其子组件3D变换的改变,并将这些改变应用到网络中的其他集群节点。
例如,在下面显示的 Actor中,当Actor移动时,DisplayClusterSceneComponentSyncParent_DefaultSceneRoot组件会跟踪并复制其父Actor的3D变换的改变。DisplayClusterSceneComponentSyncThis组件跟踪并随着其移动相对于所述场景图根同步其子立方部件的运动。
如果场景中的其他Actors在运行过程中可能会受到影响,则必须使用这两个组件中的一个将这些更改复制到所有节点。步骤如下:
1. 在“Level”视口或“ World Outliner”面板中选择需要复制的Actor 。
2. 在Details面板中,单击+ Add Component。搜索DisplayClusterSceneComponentSyncParent或DisplayClusterSceneComponentSyncThis,然后从列表中选择它。
这些组件不会执行完全复制。仅将父Actor或子组件的变换发送到集群。
六、使用VRPN输入
要在nDisplay中使用VRPN输入设备:
1. 在网络上安装VRPN服务器。
此版本的nDisplay需要VRPN 版本33。
2. 在服务器的vrpn.cfg文件中,找到服务器可执行文件旁边的文件,启用输入设备并为其命名。
3. 在nDisplay配置文件中,添加一个条目以设置VRPN输入设备,调整其坐标系,并将其附加到摄像机。
以下示例显示了设置ART DTrack跟踪系统的一种方法:
1. 在Vrpn.cfg中,位于vrpn服务器exe旁边,添加以下行:
vrpn_Tracker_DTrack DTrack 5000
这使VRPN从端口5000接收DTrack输入,并将它们映射到名为DTrack的VRPN设备。(确保DTrack配置为在端口5000上输出其追踪数据。)
2. 在nDisplay配置文件中,添加以下行:
[input] id=CaveTracking type=tracker [email protected] loc="X=1.32,Y=0,Z=0.93735" rot="P=0,Y=0,R=0" front=Z right=-X up=Y
[camera] id=camera_dynamic loc="X=0,Y=0,Z=0" tracker_id=CaveTracking tracker_ch=0
第一行创建一个名为CaveTracking的nDisplay输入设备,该设备从VRPN地址[email protected]获取数据。必须在此调整坐标系以适应追踪系统和偏移。第二行告诉nDisplay从通道0上的CaveTracking输入获取相机位置。
要从代码中管理VRPN设备的状态以及检测按钮按下等输入事件,请:
1. 在C ++中,使用IDisplayClusterInputManager类。
2. 在蓝图中,使用DisplayCluster > Input下的节点。确保在节点中设置的ID与在配置文件中设置的ID值相匹配。例如:
七、改变通信端口
nDisplay系统通过三个TCP/IP端口在主机之间进行通信:14000,14001和14002.您需要确保这些主机都被打开。
如果要自己更改端口号,可以在以下位置更改。
1. 运行时同步端口。主节点使用两个端口将数据与群集中的其他节点同步。要设置这两个端口,请在配置文件中的node_cn和port_ss配置参数中包含定义主节点的cluster_node 行。例如:
[cluster_node] id = node_front addr = 192.168.0.1 screen = screen_front viewport = vp_front port_cs = 42001 port_ss = 42002 master = true
2. nDisplay Launcher和nDisplay侦听器端口。nDisplay Launcher和nDisplay Listener都需要配置为使用相同的通信端口。启动这些应用程序时,可以在命令行中指定此项。
启动nDisplay Launcher时,请使用该listener_port参数。例如:
nDisplayLauncher.exe listener_port = 15003
此外,必须使用port参数在每个主机上启动nDisplayListener应用程序。例如:
nDisplayListener.exe port = 15003
八、将nDisplay添加到现有项目
要设置现有项目以使用nDisplay:
1. 启用nDisplay插件。
在虚幻编辑器中, 从主菜单中选择“ 编辑”>“插件 ”。搜索“nDisplay”,然后选中“已启用” 复选框。
2. 为您的项目启用nDisplay。从主菜单中
选择“ 编辑”>“项目设置”,然后找到“ 插件”>“nDisplay”部分。选中Enabled复选框。
3. 仍然在“ 项目设置”窗口中,转到“ 项目”>“说明”部分,然后选中“ 设置”>“使用无边框窗口”复选框。
4. 重新启动虚幻编辑器,重新打开项目,然后打开项目的默认关卡。
5. 在“ 世界设置”面板中,将“ 游戏模式”>“GameMode覆盖”设置设置为DisplayClusterGameModeDefault。
6. 将新的DisplayClusterSettings Actor 添加到关卡。
可以在“ 所有类”列表的“ 模式”面板中找到此Actor 。
7. 继续上面的“ 入门指南”中的其余设置说明。
九、nDisplay Launcher UI参考
本节介绍nDisplay Launcher的用户界面中提供的所有设置和选项。
控制 描述
1. Render API 指定下次单击“运行”时使用的呈现API 。
2. Render mode 指定nDisplay产生的输出类型:
Monoscopic:无立体渲染
Frame sequential:有源四路缓冲立体
Side-by-side:被动水平对齐立体
Top-bottom:被动垂直对齐立体
Monoscopic不需要任何特定的硬件功能,但帧顺序需要。确保显示设备,GPU和驱动设置与选择的渲染模式兼容。
3. Use All Available Cores 强制每个Unreal实例使用其主机上的所有可用处理器。
选择此选项后,nDisplay Launcher会将USEALLAVAILABLECORES选项添加到用于启动每个实例的命令行。
4. No Texture Streaming 禁用每个Unreal实例的纹理流。始终加载最高质量的纹理。
选择此选项后,nDisplay Launcher会将NOTEXTURESTREAMING选项添加到用于启动每个实例的命令行。
5. Custom command line arguments 如果您希望nDisplay Launcher在其用于启动每个Unreal实例的命令行上传递任何其他参数,请在此处包含它们。有关详细信息,请参阅“命令行参数参考“。
6. Applications 列出可以使用nDisplay Launcher运行的所有打包的Unreal应用程序。使用“添加”和“删除”按钮编辑列表。有关更多信息,请参阅。
7. Config Files 列出为nDisplay Launcher设置的所有配置文件。使用“添加”和“删除”按钮编辑列表。有关更多信息,请参阅“入门”的步骤3“打包和部署”。
8. Run 在选择文件所配置的所有主机上,启动选择的应用程序。
9. Kill 关闭nDisplay Launcher启动的所有虚幻引擎实例。
10. Start listeners 在“ 配置文件” 列表中选择文件所配置的每个主机上启动nDisplay Listener应用程序的实例 。
11. Stop listeners 关闭此nDisplay Launcher启动的nDisplay Listener应用程序的所有实例。
12. Deploy application 将“ 应用程序”列表中选择的应用程序复制到“ 配置文件” 列表中选择文件所配置的每个主机 。
13. Copy 将日志窗口中列出的所有消息复制到剪贴板。
14. Clean 清除日志窗口左侧的所有消息。