目录
- 1 创建一个AR场景
- 2 配置AR Camera为前置摄像头
- 3 配置打包场景
- 4 下载官方提供的InteractiveFaceFilterAssets资源
- 5 配置AR Face Manager
- 6 创建眼镜预制件
- 7 设置AR面部追踪
- 8 测试效果
- 9 在该AR场景的基础上添加自己的想法
- 10 配置UI界面
- 11 使用Visual Scripting实现交互
- 12 资源合集下载
1 创建一个AR场景
接着上篇文章的创建一个AR脸部特效安卓程序,这次来创建一个自己的可交互AR程序。同样使用之前的项目,在Assets的Scene文件夹下使用Ctrl+N新建一个Scene(或者File→New Scene),选择AR场景,点击Create创建:
2 配置AR Camera为前置摄像头
这里由于也是对人脸进行识别,因此也需要使用移动设备的前置摄像头
- 在Hierarchy中找到AR Session Origin物体,展开其折叠物体并找到AR Camera物体。
- 在AR Camera的Inspector面板中找到AR Camera Manager组件,将其中的Facing Direction属性设置为User:
3 配置打包场景
菜单栏选择File → Build Settings,将新建的场景加入到打包列表中,隐藏或删除之前的场景:
4 下载官方提供的InteractiveFaceFilterAssets资源
zip下载位置在此,点击即可下载。
下载完成解压后,即可将InteractiveFaceFilter.unitypackage导入工程的Assets文件夹下。
导入方法:
在zip文件解压的文件夹位置,找到其中的unitypackage,将其拖拽至Unity的Assets文件夹上,接着会跳出一个导入资源的窗口,点击右下角的Import导入。
导入的资源:
- Meshes:其中有五副风格各异的眼镜模型。
- Prefabs:AR_Canvas预制体,是用于交互的UI。
- Resources:其中包含PSD格式的UI模板,用于创建我们自己的。
- Sprites:包含用于创建用户界面的UI。
5 配置AR Face Manager
这一步中,我们将使用AR Face Manager来告知AR Session Origin,当检测到面部时,脸上将会显示什么特效。
-
将Hierarchy中的Cube物体删除,它只是用于测试的。
-
选中AR Session Origin物体,在其Inspector窗口中搜索并添加AR Face Manager组件,该组件用于检测人脸:
6 创建眼镜预制件
这一步中,为所有可选的眼镜创建一个预制体,称为“GlassesGroup”,用于用户选择眼镜。
- 在Assets文件夹中找到_InteractiveFaceFilter → Meshes,拖拽你想实装到移动设备的三副眼镜到Hierarchy窗口,并在Inspector面板中将它们的位置设置为(0,0,0)。
- 在选中三副眼镜的状态下右键Creat Empty Parent为这三副眼镜创建一个空父物体,并将空物体的命名为“GlassesGroup”。
7 设置AR面部追踪
为了使得眼镜能正好出现在眼睛的位置,我们需要将GlassesGroup做成AR Face预制体。
-
在Inspector面板中为GlassesGroup添加AR Face组件,用于GlassesGroup追踪人脸的移动:
-
将Hierarchy中的GlassesGroup拖拽至Assets → _InteractiveFaceFilter → Prefabs中做成预制体:
-
将该制作好的预制体拖拽至AR Session Origin物体AR Face Manager组件的Face Prefab中:
8 测试效果
8.1 在Unity中测试
首先确保Game视图是适配手机的16:9分辨率,接着回到Scene窗口中,在Hierarchy窗口中选择GlassesGroup物体,将它的位置Z轴改为0.4,以便它可以显示在Game窗口的中心:
同样的,为了让这些眼镜出现在移动设备的视野中心,需要将GlassesGroup预制体的PositionZ轴也修改为0.4:
8.2 在安卓设备上测试
如果在Unity中测试,那么使用的是Hierarchy中的GlassesGroup预制体;而如果要在安卓移动设备上测试,那么需要隐藏Hierarchy中的GlassesGroup预制体。
- 隐藏Hierarchy中的GlassesGroup预制体。
- 项目配置参考这篇文章的第3.2节。
- Ctrl+S保存场景,菜单栏File → Build Settings,选择Buid打包apk,导出到安卓设备中测试。
- 程序打开并检测到人脸后,三幅眼镜都将显示在脸上。
9 在该AR场景的基础上添加自己的想法
9.1 改变眼镜模型的大小
项目中的眼镜模型是以一般人脸为基准设定的大小,我们可以修改眼镜的大小比例或者加以旋转,使得它们变得更加有趣。
9.2 从网上导入新的模型
在诸如Sketchfab等网站上有很多眼镜的模型,可以下载后导入项目中。在模型选择上,有以下3个大体的考量:
- 模型格式。需确保模型的格式是Unity支持的,如FBX格式。
- 模型的复杂度:最好不要找过于复杂、面数太多的模型,这对于移动的优化很不友好。
- 模型的使用许可:注意模型会有一个CC许可证,其中会具体说明艺术家允许使用其中的哪些内容。关于CC许可证详见此处。
如可以使用这个蒸汽朋克眼镜资源,作者Kisielev Mikhail,在知识共享署名下授权。
9.3 制作自己的模型
制作自己的眼镜模型可以考虑以下几点:
- 只包括眼镜的正面:我们总是能看到眼镜模型的所有部分,所以当用户转头时,镜腿可能会与耳朵重叠,破坏沉浸感。我们可以只建模到眼镜会绕过耳朵的地方,但是如果用户的脸稍微长一点,模型可能就不会碰到他们的耳朵。
- 保证模型的面数处于一个较低的范围:由于最终项目是在移动设备上应用,所以模型应该尽可能地优化。
- 将模型限制在一种材质上:由于后续我们将实现改变眼镜颜色的功能,因此需要把它们限制在一种材质上。
- 模型的原点与方向:我们创建的眼镜模型原点需要位于系统的原点,且眼镜的朝向需要对准AR面部。可以将Face_Reference_Mesh模型导入作为参考。
10 配置UI界面
10.1 添加AR_Canvas预制体
该项目使用UGUI系统,即所有的UI都使用Canvas组件来管理,它们都是Canvas的子物体。
- 在Assets中找到 _InteractiveFaceFilter → Prefabs下的AR_Canvas预制体,并将其拖拽至Hierarchy窗口。
- 可以在Game窗口查看UI的展现效果:
AR_Canvas是以Screen Space为Overlay的方式渲染的,这就表示它始终渲染在其他的物体之上,并能准确地在Game窗口中显示在固定位置。 - AR_Canvas由3个子物体组成:Glasses Buttons和Materials Buttons用来分别控制眼镜和眼镜材质的切换。而EventSystem用于检测用户的输入。
10.2 定制眼镜按钮
现在眼镜切换按钮都是以圆圈的形式表示,为了让用户能更直观地分辨哪个按钮切换到哪一副眼镜,需要将圆圈替换为特定的眼镜图标。
Unity中使用sprite sheet来存放一个图集,它可以被切片,以便图像能单独在Unity中使用:
- 在Assets中找到 _InteractiveFaceFilter → Sprites 下的 UI_Icon_Glasses 图集,点击它旁边的“>”展开它,可以观察到被切片的Sprites。
- 将眼镜图标与眼镜按钮对应起来。使用拖拽sprite到按钮的Image组件下的Source Image中实现:
10.3 定制材质按钮
为了使眼镜更加美观,这里需要定义不同的材质(颜色)按钮:
- 在Hierarchy窗口中展开Materials Buttons,并找到其下的3个子物体,分别修改Image组件下的Color。
- 最终效果如下:
10.4 其他尝试
我们还可以做如下的一些尝试:
-
把按钮移动到用户界面的其他位置如顶部:修改图标组件的Rect Transform组件或直接使用快捷键W移动至合适位置。
-
制作自己的眼镜图标: 如果使用的是自己制作的眼镜模型,那么可以通过修改PSD文件UI_Icon_Glasses_Template来实现制作自己的眼镜图标
11 使用Visual Scripting实现交互
11.1 Visual Scripting简介
我们可以使用Visual Scripting为项目创建逻辑功能,这是一种可视化逻辑的方式。
如下左图和右图是一样的逻辑表达:
Visual Scripting还为非编码人员提供了对整个Unity Scripting应用编程接口(API)的访问。这个API包含了可以在Unity脚本中操作的类、事件、方法(行为)和属性(设置)的全套定义。
11.2 创建一个graph
可视化脚本是存储于图(graph)中的,它可以以组件的形式应用于任意的GameObject上。
1.在Hierarchy中Create Empty创建一个空物体,确保其坐标在(0,0,0)位置,将其命名为“Visual Scripts”。
2.在“Visual Scripts”的Inspector窗口中添加“Script Machine”组件。
“Script Machine”组件是用于运行可视化脚本的工具。
- 选择“New”新建一个Graph,并命名为“MeshChanger”保存在新建的“Visual Scripts”文件夹下。
- 可以观察到新建的“MeshChanger”图出现在“Script Machine”组件的Graph参数中,且出现了两个新的参数:标题(Title)和摘要(Summary)。这两个参数可以用于分辨不同的“Script Machine”。
- 修改Title和Summary如下,表明该可视化脚本的用途:
11.3 编辑可视化脚本
11.3.1 点击按钮控制台输出信息
-
在“Script Machine”组件中点击Edit Graph以打开可视化脚本工作区。如果是第一次打开,会跳出一个对话框,选择Change now即可。
且一个名为VisualScripting SceneVariables的新GameObject将在Hierarchy中自动生成。
-
节点是用来构建图中逻辑的组件,有几种不同类型的节点。每当创建一个新图时,它将加载On Start和On Update节点。
Script Graph窗口右侧是Graph Editor,在这里建立图形逻辑;窗口左侧是Graph Inspector,它将为我们展示选择对象的详细信息;在图形检查器窗口的下面是Blackboard,在这里创建变量。 -
Graph Editor中的操作:
- 鼠标中键按住可以拖动视图控制移动;
- 按住Ctrl键并滚动鼠标滚轮可以缩放视图。
- 鼠标右键可以新建新的节点。
-
选中On Start节点,左侧的Inspector窗口中列出了该节点有一个称作“Trigger”的Output(输出)。流程(Flow)的inputs(和outputs)决定了图的逻辑流程。
-
这里我们需要实现的功能不需要使用到On Start和On Update节点。因此,选中它们后右键选择Delete删除或者直接按Delete键删除。
-
右键创建一个On Button Click节点或者点击Events > GUI > On Button Click创建:
与之前的On Start和On Update节点不同,On Button Click有一个Inputs部分。有两种类型的输入:控制输入和数据输入。
- 控制输入控制图形的逻辑流程。
- 数据输入从其他节点接收特定类型的值,接收节点需要这些值来执行其任务。
On Button Click节点只在按钮被按下时执行事件,因此它需要知道它应该监视哪个按钮。
Graph Inspector窗口中,On Button Click节点的输入正在寻找一个GameObject目标,这个GameObject就是On Button Click节点将监视的输入按钮。
默认情况下,On Button Click节点有一个标有This的参数,这个参数是目标输入将被连接的地方。当没有连接输入节点时,该节点有一个保护措施:它将在它所分配的游戏对象上寻找目标输入。
在这种情况下,如果把参数留空,On Button Click节点就会在我们创建的Script Machine所附的Visual Scripts GameObject上寻找一个Button组件。如果脚本图被附在AR_Canvas的一个按钮上,那么这就没问题了;
但是如果Graph在不同的GameObjects上,那么就需要使用变量来控制。
Variables是不同种类数据的容器。这些数据可以是数字、GameObjects、声音,或者其他任何东西。变量可以在graph本身中生成,也可以作为应用程序中其他对象的引用。在本例中,我们将创建一个变量,它将引用用户界面上的一个按钮。
-
创建一个变量。变量是在Blackboard中创建的,Blackboard顶端有如下的一些标签:
- Graph
- Object
- Scene
- App
- Saved
这些标签是我们可以创建的不同类别变量。因为我们需要创建一个引用场景中GameObject的变量,因此我们将创建一个Object变量。
-
首先,选择Object标签,输入 “glasses1Button” 后点击“+”号或按“Enter”添加变量;接着,将该变量的类型(Type)设置为Button、其Value参数选择Hierarchy中的Glasses1Button;最后,将Blackboard中创建的 “glasses1Button” 变量拖拽至Graph中,变成Get Variable节点。
Glasses1Button的Get Variable节点上也有This参数,这和On Button Click一样,是在Get Variable的返回值没有填写情况下的一个后备选项。但由于这个节点被定义为glasses1Button,所以不需要有返回值。 -
连接Get Variable节点与On Button Click节点,这样就实现了检测Glasses1Button按钮被按下这个事件了。
可以观察到,On Button Click节点上的This值消失了,这是因为它现在接受到了glasses1Button这个变量。
这样连接之后,点击Play运行项目就会发现在点击第一个眼镜图标时,On Button Click节点在闪烁,这说明它接收到了按钮的点击。 -
而要在点击按钮后在Console窗口中输出一条信息,那么可以在Graph中添加 Debug Log (Message) 节点以及String Literal节点用来输出一条文本信息。
其中,Debug Log (Message) 节点的作用是想Unity的控制台输出一条信息。该节点有一个Flow和Object输入,Object输入的内容是转换为字符串表示的字符串或对象,这样方便显示。因此需要创建一个String Literal(字符串)节点。
将On Button Click节点右侧的Flow输出连接到Debug Log节点左侧的Flow输入,接着将写有“Button 1 pressed!”的String Literal节点的输出连接到Debug Log节点左侧的Message输入。
运行可以发现控制台在检测到按钮按下后输出了“Button 1 pressed!”
另外,可以尝试使用Get Name、String、Concat节点进行获取GameObject名并将字符串拼接输出:
11.3.2 点击按钮触发显示模型事件
-
为了达到点击按钮出现眼镜模型的效果,需要先将眼镜模型的Mesh Renderer组件禁用,这个组件用于管理一个GameObject的可见性。
-
在Unity中,有几种在脚本中快速定位到指定GameObject的方法。其中一种方法是为GameObject分配一个独有的tag,即标签。这里为三幅眼镜分别添加一个特有的标签以更好地识别与分辨它们。
-
在Hierarchy窗口中,选择GlassesGroup物体,在其Inspector窗口中选择Overrides右侧的下拉菜单并点击Apply All以将标签设置保存到预制体中。
-
更新script graph,为了通过tag识别游戏物体,需要使用到Find With Tag节点。
可以看到该节点返回场景中一个active的GameObject,由于之前我们只是禁用了眼镜模型的mesh renderers,它们仍是处于active状态,因此是可以使用Find With Tag找到的。该节点需要一个数据(Flow)输入,也就是要查找的标签的名称。 -
连接On Button Click节点的数据(Flow)输出和Find with Tag节点的数据(Flow)输入。
-
使用Mesh Renderer:Set Enabled节点来实现用户点击按钮显示眼镜模型功能
该节点详细信息如下:
可以观察到需要两个数据来使用这个节点:
- Target:该节点所要响的特定mesh renderer
- Value:该mesh renderer被启用或禁用,如果Bool值被设置为true(启用),那么指定的Mesh Renderer就会被启用。如果Bool值被设置为false(禁用),那么Mesh Renderer将被禁用。
-
连接Find with Tag节点的数据(Flow)输出和Set Enabled节点的输入,连接Find with Tag节点的result输出和Set Enabled节点的输入,并将Bool值打勾。这表示当点击到按钮时,特定标签的眼镜模型会显示。
点击Play测试时就会发现点击第一个按钮,按钮上显示的眼镜也会出现在场景中。 -
复制两份制作好的script graph,并增加两个Object变量,拖动剩余两个按钮到其Value上,将Get Variable节点上相应的值修改。接着修改Find with Tag节点的Tag值为之前设置的眼镜特定tag。
点击Play测试时会发现点击按钮后眼镜依次出现在场景中,但是它们是叠加在一块的,这是因为还没有添加使它们隐藏的功能。
接着可以打包成apk到安卓设备上运行测试,注意需要将Hierarchy中的GlassesGroup禁用。
11.3.3 点击按钮触发切换模型事件
由于上一小节中,眼镜模型叠加在一块出现,因此需要使用Mesh Renderer:Set Enabled节点来禁用眼镜模型的可见性。
-
复制script graph中三个按钮的Find With Tag节点和Set Enabled节点,并将Set Enabled节点上的勾去掉。
-
修改script graph,使得用户点击任一按钮时,所有的眼镜模型都不显示。由于visual script运行的很快,因此顺序运行的隐藏眼镜在我们看起来是同时隐藏的。
-
接下来需要将上述相连的节点放到如下图中箭头所指的流程中,因为要在显示对应眼镜模型前将所有眼镜模型都隐藏。
但是可见,上图红框中的序列比较长,因此需要将该序列转换为一个自定义事件,这样我们就可以将他作为一个单一的节点以便调用该事件。 -
新建一个Custom Event节点,命名为“DisableRenderers”,并将其右侧输出流连接到上述序列的左侧输入流。
可以从graph Inspector面板中观察到,Custom Event节点的输入流可以是GameObject或String。
这里使用一个字符串“DisableRenderers”来命名该自定义事件,之后将使用该名称来调用该事件。 -
使用Trigger Custom Event节点来调用上述自定义事件。新建一个Trigger Custom Event节点,并复制两个。使用鼠标右键点击节点的输出流或输入流以取消连接,并将该节点插入OnButtonClick节点后。
我们可以把Trigger Custom Event节点当作一个链接(link),当这个节点被调用时,它将启动它所关联的自定义事件中的节点序列。
点击Play在编辑器中运行测试可以发现,点击对应的按钮,就会出现相应的模型,且不是叠加出现。
接着可以打包成apk到安卓设备上运行测试,注意需要将Hierarchy中的GlassesGroup禁用。
11.3.4 点击按钮触发切换模型颜色事件
在使用script graph为GameObject添加逻辑功能时,最好是一个graph实现一个功能,这样graph就不会杂乱无章了。
-
在Hierarchy面板中,选中Visual Scripts物体,并在其Inspector面板中点击Add Component为其再添加一个“Script Machine”组件。接着,点击New,将该Visual script命名为“Material Changer”,并在其Title栏中填写“Material Changer”,在其Summary栏中填写“Changes the material assigned to all of the glasses when the material buttons are selected.”表示该可视化脚本用于实现点击按钮,变换眼镜模型的材质。
-
同样的,在这个功能中,我们不需要使用到On Start节点以及On Update节点,因此选中它们后按delete键删除。首先,新建一个On Button Click节点,并在blackboard中为它设置一个Object变量用于获取变化材质按钮。
-
在Assets下的_InteractiveFaceFilter文件夹中创建一个新文件夹,并命名为 “Materials”。新建对应按钮颜色的三种颜色材质,分别命名为“Material1”、“Material2”和“Material3”。
-
在blackboard中,创建三个Object类型的变量用来引用三种材质,它们的类型是Material,将它们分别命名为“Material1”、“Material2”和“Material3”。
-
要改变眼镜模型的颜色,需要获取到眼镜模型,再对其材质进行修改。因此,需要用到Find With Tag节点使用特定tag获取对应眼镜模型。
-
使用Mesh Renderer: Set Material节点来更改眼镜模型的材质。
Set Material节点有两个输入:
- Target:它要改变的GameObject的引用。
- Value:要应用的材质。
其中Target使用从Find With Tag节点获取到的眼镜模型,Value使用对应材质的变量:
- 复制两份Find With Tag节点以及Set Material节点,并把其中的tag修改为另外两副眼镜的标签。如下图所示相连,这样第一个材质就可以同时应用到三副眼镜上了:
点击Play测试,可以发现第一个材质可以赋予三副眼镜:
同样的方式,可以将另外两个颜色材质的赋予功能添加到script graph中。但是这里其实用到了重复的节点序列,因此下一节中使用带参数的自定义事件进一步将另外两个材质的功能添加进来。
11.3.5 创建自定义事件并使用参数调用
-
首先,需要将所有的“Find With Tag”节点以及“Set Material”节点分离到Custom Event中,这样在每个材质修改按钮按下时就可以通过调用事件调用它们了。
-
参数可以被传递到事件或函数中,以改变事件的结果或函数的输出。由于我们需要对眼镜模型应用三种不同的材质,这取决于是哪个按钮被点击了。为Custom Event节点添加一个数据输出,称为参数,将不同的数据传递给那些Set Material节点。
-
调用定义的ChangeMaterial事件需要使用Trigger Custom Event节点,同样的,它也需要一个参数。
这时点击Play测试,也是同样的将第一种材质赋予三副眼镜。 -
复制两次第3步中的节点,分别将两个Get Variable节点中的按钮和材质修改为另外两个按钮和材质。
点击Play按钮在编辑器中测试,所有的按钮都发挥了作用。
接着,就可以禁用Hierarchy中的GlassesGroup物体,打包到安卓设备上测试了。可以观察到,眼镜可以追人脸的移动而移动。
11.3.6 将用户的选择加载
在上一节的测试中,可以发现用户的头一旦离开了屏幕,再返回查看时,之前的眼镜不会再重新出现在脸上了。这是因为我们没有保存用户的选择,用户的脸离开屏幕后,AR Face Manager会将GlassesGroup组件删除;而当用户的脸再次回到屏幕前,AR Face Manager会重新实例化一个GlassesGroup预制体,它只有默认的设置配置,也没有将之前用户选择的材质应用到眼镜模型上。
- 首先,需要确保Hierarchy中的GlassesGroup物体是启用状态,接着编辑MeshChanger可视化脚本,在blackboard中创建一个名为“currentGlassesTag”的String类型变量(Object)用来存储用户当前选择的眼镜tag,并在graph中通过搜索“Set currentGlassesTag”找到“currentGlassesTag”变量的Set Variable节点。
为了在初始化时,避免找不到tag的情况,将“currentGlassesTag”变量的Value值设置为第一个眼镜的tag,这里为mask。
-
由于currentGlassesTag的值需要根据用户选择的按钮进行变化,因此我们需要创建一个名为“SaveTag”的custom event,使它可以被三个按钮调用,它有一个参数用于输出获取到的tag。再添加一个获取物体Tag的节点,用于获取当前模型的tag。
-
使用Trigger Custom Even节点调用获取到tag的SaveTag事件,将其参数数量也修改为1,并作如下连接:
-
在之前的步骤中,我们获取了当前用户选择的是哪副眼镜的引用。因此,这一步中我们将在新的GroupGlasses预制体被实例化时,将用户选择的眼镜应用到GroupGlasses上。
这里,在Script Machine上再创建一个名为“FilterUpdater”的Graph,并在其Title栏目中填写“Filter Updater”,在其“Summary”栏目中填写“Reloads the last worn pair of glasses and selected material after a user’s face is lost and rediscovered by AR Foundation”,表示在用户的脸移开摄像头后重新加载之前选定的眼镜和材质。
-
先删除其中的On Start节点,保留On Update节点,因为我们需要实时检测用户的脸是否在摄像机的检测范围内。当应用程序运行时,On Update节点将持续地运行。FilterUpdater图的功能是通过currentGlassesTag变量获取当前用户选择的眼镜模型并将其Mesh Renderer启用。
-
可以通过这样的方式在编辑器中测试以上脚本的功能:
- 点击Play按钮运行程序,这时会发现FilterUpdater图中的Find With Tag节点变成了红色,这时因为在应用在实时查找一个具有特定标签的对象,但是该标签还是空的。
- 因此,在Game窗口中,任意选择一个眼镜按钮,这样currentGlassesTag变量中就有值了。
- 接着,在Hierarchy窗口中,选择GlassesGroup预制体并将其删除。
- 最后,在Project窗口中,在 Assets → _InteractiveFaceFilter → Prefabs下重新拖动GlassesGroup预制体到Hierarchy窗口中,这时会发现之前选择的眼镜模型又出现了。
-
同样的方式,选择编辑MaterialChanger图,在blackboard中创建一个名为“currentMaterial”的Material类型变量(Object)用来存储用户当前选择的眼镜材质,并在graph中通过搜索“Set currentMaterial”找到“currentMaterial”变量的Set Variable节点。
-
由于之前已有ChangeMaterial的Cutom Event用来传递用户选择的材质,直接使用Set Variable节点获取即可:
-
最后,回到FilterUpdater图中,使用Mesh Renderer Set Material节点实时更新将用户已选择的材质赋予给眼镜模型:
-
如果这时候点击Play进行测试,会发现当选择了一副眼镜,眼镜上的材质缺失了,这是因为开始时用户并没有选择眼镜的材质,导致currentMaterial变量的值为空。因此需要为currentMaterial变量设置一个初始值。
-
在blackboard中找到currentMaterial变量,将其Value值设置为Lambert1,即默认为灰色的材质。
-
重新点击Play测试后,会发现一切正常显示了。接着,可以禁用Hierarchy中的GlassesGroup预制体,打包到安卓设备上进行测试。
12 资源合集下载
来源地址:https://blog.csdn.net/qq_41084756/article/details/129873035