URP渲染管线下的 huawei AREngine预览流绘制
huawei AREngine 默认的 builtin 的渲染管线绘制预览流, 在如今行业普遍使用的自定义渲染管线有点儿过时。 看 ARFoundation 的实现, 已经默认支持builtin和urp的无缝切换, 于是就想着把 AREngine 的预览流绘制使用urp来实现一遍。
builtin的预览流实现:
首先预览流信息直接由GPU端直传到 glsl(shader)里了, 这个不需要经过cpu, 比如说转yuv这些格式, 这个效率是非常高了, 像官方c#里的代码的实现很多都是冗余的代码, 完全没有必要且可以删减。
真正传递camera信息过来是在glsl里使用了特使的标记 samplerExternalOES:
uniform samplerExternalOES _MainTex;
关于Android是如何获取预览流并绑定纹理具体可以参考链接。
在使用 samplerExternalOES 纹理前, 需要开启camera, 这个步骤既可以通过 AREngine的 SesssionComponent 组件, 也可以使用 unity 自带的 WebCamera来实现。 获取到纹理之后, 如何显示在屏幕上呢?
AREngine 使用的 CommandBuffer Blit, 这点跟 ARCore是一致的, 且绑定了 BeforeForwardOpaque、BeforeGBuffer 两个Event, 分别对应 前向渲染 和延时渲染。
m_VideoCommandBuffer = new CommandBuffer();
m_VideoCommandBuffer.Blit(BackGroundMaterial.mainTexture, BuiltinRenderTextureType.CurrentActive,
BackGroundMaterial);
m_Camera.AddCommandBuffer(CameraEvent.BeforeForwardOpaque, m_VideoCommandBuffer);
m_Camera.AddCommandBuffer(CameraEvent.BeforeGBuffer, m_VideoCommandBuffer);
urp 渲染实现预览流
如果在urp管线中再想上述代码一样实现, 把BackGroundRenderer.cs 挂载在 scene 里就行不通了。 urp Renderer Feature可让我们向URP Renderer添加额外的渲染通道,支持我们进行Asset资产配置来重写从而可以自定义渲染的顺序、渲染的对象、材质等等。 关于详细的 Render Feature 详细的介绍, 参考unity官方的课程。
这里就新建立个 ARBackgroundRenderFeature 的 RenderFeature, 并配置在 Render的管线中:
在 相应的 RenderPass里传入 ARBackground的材质, 由于只有前向渲染, 这里的renderPassEvent选取的是BeforeRenderingOpaques。 在执行函数Execute里 封装一个 CommandBuffer 专门用来绘制 预览流。具体的实现参考:
public class ARBackgroundRenderPassFeature : ScriptableRendererFeature
{
[System.Serializable]
public class Settings
{
public Material material;
public RenderPassEvent Event = RenderPassEvent.AfterRenderingOpaques;
}
class CustomRenderPass : ScriptableRenderPass
{
private Settings _settings;
public CustomRenderPass(Settings sts)
{
_settings = sts;
renderPassEvent = sts.Event;
}
// Here you can implement the rendering logic.
// Use <c>ScriptableRenderContext</c> to issue drawing commands or execute command buffers
// https://docs.unity3d.com/ScriptReference/Rendering.ScriptableRenderContext.html
// You don't have to call ScriptableRenderContext.submit, the render pipeline will call it at specific points in the pipeline.
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
if (_settings.material != null)
{
CommandBuffer cmd = CommandBufferPool.Get();
cmd.Blit(_settings.material.mainTexture, BuiltinRenderTextureType.CurrentActive, _settings.material);
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
CommandBufferPool.Release(cmd);
}
}
// Cleanup any allocated resources that were created during the execution of this render pass.
public override void OnCameraCleanup(CommandBuffer cmd)
{
}
}
}
由于我们使用glsl shader里指定的平台是 gles3, 所以这里正确执行在会在Android手机侧能保证正确, 在PC平台得到的结果是紫色的。
#ifdef SHADER_API_GLES3
#pragma only_renderers gles3
#extension GL_OES_EGL_image_external_essl3 : require
#endif
不过倒是可以额外使用一个shader 用来仿真手机的运行的结果, 在pc平台只显示一张图片来代替手机上的预览流, 作者已经 EditorBackground.shader 做好上传到 github, 读者根据自己的使用需求处理就可以了。 为了更接近手机上的结果, 使用的shader还是 使用的是glsl语言, 并不是更常用的 cg 或者 hlsl, 因此pc运行的时候也需要切换到 OpenGL 平台, 只需要在 EditorSetting 如下图处理即可:
Graphic Setting 切换完毕置换后, 注意重启unity。
结语
AREngine 项目完全切换到 URP 渲染管线, 不单单是预览流的处理, 参与渲染的其他部分也需要做出相应的更改, 读者根据自己的实际项目需求进行调整, 也期望在使用urp过程中遇到或者解决相关的问题心得跟作者沟通。