文章目录

  • 1.前言
  • 2.ARCore流程
  • 3.渲染流程
    • 3.1 数据更新
    • 3.2 渲染
  • 4.结语

1.前言

像Vuforia、ARCore、EasyAR等sdk,使用时都会将背景与虚拟进行叠加。此功能的实现有很多种,比如直接在Camera的远平面附近添加一个UI或者quad,将camera的画面付给它;比如用CommandBuffer将画面最先渲染;或者重写shader,更改渲染顺序或者设置深度值。ARCore采用的CommandBuffer的方式,但是里面有很多细节需要说明。

2.ARCore流程

ARCore背景渲染脚本为ARCoreBackgroundRenderer,其基本流程为:
1)OnEnable时初始化CommandBuffer
2)Update中实时更新材质的属性,比如相机背景的Texture
3)OnDisable时移除CommandBuffer。
第一步和第三步比较简单,如下代码所示:

       private void EnableARBackgroundRendering(){if (BackgroundMaterial == null || m_Camera == null){return;}m_CameraClearFlags = m_Camera.clearFlags;m_Camera.clearFlags = CameraClearFlags.Depth;m_CommandBuffer = new CommandBuffer();#if UNITY_ANDROIDif (SystemInfo.graphicsMultiThreaded && !InstantPreviewManager.IsProvidingPlatform){m_CommandBuffer.IssuePluginEvent(ExternApi.ARCoreRenderingUtils_GetRenderEventFunc(),(int)ApiRenderEvent.WaitOnPostUpdateFence);
#if UNITY_2018_2_OR_NEWER// There is a bug in Unity that IssuePluginEvent will reset the opengl state but it// doesn't respect the value set to GL.invertCulling. Hence we need to reapply// the invert culling in the command buffer for front camera session.// Note that the CommandBuffer.SetInvertCulling is only available for 2018.2+.var sessionComponent = LifecycleManager.Instance.SessionComponent;if (sessionComponent != null &&sessionComponent.DeviceCameraDirection == DeviceCameraDirection.FrontFacing){m_CommandBuffer.SetInvertCulling(true);}
#endif}#endifm_CommandBuffer.Blit(null,BuiltinRenderTextureType.CameraTarget, BackgroundMaterial);m_Camera.AddCommandBuffer(CameraEvent.BeforeForwardOpaque, m_CommandBuffer);m_Camera.AddCommandBuffer(CameraEvent.BeforeGBuffer, m_CommandBuffer);}
        private void DisableARBackgroundRendering(){if (m_CommandBuffer == null || m_Camera == null){return;}m_Camera.clearFlags = m_CameraClearFlags;m_Camera.RemoveCommandBuffer(CameraEvent.BeforeForwardOpaque, m_CommandBuffer);m_Camera.RemoveCommandBuffer(CameraEvent.BeforeGBuffer, m_CommandBuffer);}

3.渲染流程

渲染流程从如下两个方面讲解,第一个为数据层,即update方法中实时更新的参数;第二个为渲染层,即CommandBuffer使用材质(shader)。

3.1 数据更新

背景渲染时每帧的数据更新如下流程:
1)设置_Brightness,通过此变量实现背景出现时由默认ICON切换到Camera背景的一个小动画。
2)设置_TransitionIconTexTransform,此变量根据默认icon和屏幕大小计算出。如果默认Icon长宽超出屏幕,保证正确裁剪,根据注释以及shader,其计算也是先按比例缩放,然后在平移到中心位置。计算如下:

        /// <summary>/// Textures transform used in background shader to get texture uv coordinates based on/// screen uv./// The transformation follows these equations:/// textureUv.x = transform[0] * screenUv.x + transform[1],/// textureUv.y = transform[2] * screenUv.y + transform[3]./// </summary>/// <returns>The transform.</returns>private Vector4 _TextureTransform(){float transitionWidthTransform = (m_TransitionImageTexture.width - Screen.width) /(2.0f * m_TransitionImageTexture.width);float transitionHeightTransform = (m_TransitionImageTexture.height - Screen.height) /(2.0f * m_TransitionImageTexture.height);return new Vector4((float)Screen.width / m_TransitionImageTexture.width,transitionWidthTransform,(float)Screen.height / m_TransitionImageTexture.height,transitionHeightTransform);}

注释中有说明如何使用这四个参数。
3)传入视频流Texture,即设置_MainTex。此_MainTex是通过Texture2D.CreateExternalTexture生成的android OES类型texture,并非传统的glTexture,所以在采样时使用的是samplerExternalOES。此Texture通过Frame.CameraImage.Texture获取,并非AcquireCameraImageBytes方法获取的ImageBytes,此ImageBytes为YUV格式数据,并且大小只有640*480;
4)传入_UvTopLeftRight和_UvBottomLeftRight值,此两个值跟2)类似,因为uv并非完全匹配。

3.2 渲染

渲染所用的shader为ARCore/ARBackground,此shader较为简单,有两个pass。第一个pass采用GLSL编写,为了从OES纹理采样,并基于输入的参数进行uv裁切(包括初始ARIcon以及_MainTex)。第二个pass则进行最简单的uv采样,不过采样时反转了x值

Shader "ARCore/ARBackground"
{Properties{_MainTex ("Main Texture", 2D) = "white" {}_UvTopLeftRight ("UV of top corners", Vector) = (0, 1, 1, 1)_UvBottomLeftRight ("UV of bottom corners", Vector) = (0 , 0, 1, 0)}// For GLES3 or GLES2 on deviceSubShader{Pass{ZWrite OffCull OffGLSLPROGRAM#pragma only_renderers gles3 gles// #ifdef SHADER_API_GLES3 cannot take effect because// #extension is processed before any Unity defined symbols.// Use "enable" instead of "require" here, so it only gives a// warning but not compile error when the implementation does not// support the extension.#extension GL_OES_EGL_image_external_essl3 : enable#extension GL_OES_EGL_image_external : enableuniform vec4 _UvTopLeftRight;uniform vec4 _UvBottomLeftRight;// Use the same method in UnityCG.cginc to convert from gamma to// linear space in glsl.vec3 GammaToLinearSpace(vec3 color){return color *(color * (color * 0.305306011 + 0.682171111) + 0.012522878);}#ifdef VERTEXvarying vec2 textureCoord;varying vec2 uvCoord;void main(){vec2 uvTop = mix(_UvTopLeftRight.xy,_UvTopLeftRight.zw,gl_MultiTexCoord0.x);vec2 uvBottom = mix(_UvBottomLeftRight.xy,_UvBottomLeftRight.zw,gl_MultiTexCoord0.x);textureCoord = mix(uvTop, uvBottom, gl_MultiTexCoord0.y);uvCoord = vec2(gl_MultiTexCoord0.x, gl_MultiTexCoord0.y);gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;}#endif#ifdef FRAGMENTvarying vec2 textureCoord;varying vec2 uvCoord;uniform samplerExternalOES _MainTex;uniform sampler2D _TransitionIconTex;uniform vec4 _TransitionIconTexTransform;uniform float _Brightness;void main(){vec3 mainTexColor;#ifdef SHADER_API_GLES3mainTexColor = texture(_MainTex, textureCoord).rgb;#elsemainTexColor = textureExternal(_MainTex, textureCoord).rgb;#endifif (_Brightness < 1.0){mainTexColor = mainTexColor * _Brightness;if (_TransitionIconTexTransform.x > 0.0 &&_TransitionIconTexTransform.z > 0.0){vec2 uvCoordTex = vec2(uvCoord.x *_TransitionIconTexTransform.x +_TransitionIconTexTransform.y,uvCoord.y *_TransitionIconTexTransform.z +_TransitionIconTexTransform.w);vec4 transitionColor = vec4(0.0);if (uvCoordTex.x >= 0.0 &&uvCoordTex.x <= 1.0 &&uvCoordTex.y >= 0.0 &&uvCoordTex.y <= 1.0){transitionColor = texture2D(_TransitionIconTex,uvCoordTex);}if (transitionColor.a > 0.0){mainTexColor = mix(transitionColor.rgb,mainTexColor,_Brightness);}}}#ifndef UNITY_COLORSPACE_GAMMAmainTexColor = GammaToLinearSpace(mainTexColor);
#endifgl_FragColor = vec4(mainTexColor, 1.0);}#endifENDGLSL}}// For Instant PreviewSubshader{Pass{ZWrite OffCGPROGRAM#pragma exclude_renderers gles3 gles#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"uniform float4 _UvTopLeftRight;uniform float4 _UvBottomLeftRight;struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;};v2f vert(appdata v){float2 uvTop = lerp(_UvTopLeftRight.xy,_UvTopLeftRight.zw, v.uv.x);float2 uvBottom = lerp(_UvBottomLeftRight.xy,_UvBottomLeftRight.zw, v.uv.x);v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.uv = lerp(uvTop, uvBottom, v.uv.y);// Instant preview's texture is transformed differently.o.uv = o.uv.yx;o.uv.x = 1.0 - o.uv.x;return o;}sampler2D _MainTex;fixed4 frag(v2f i) : SV_Target{return tex2D(_MainTex, i.uv);}ENDCG}}FallBack Off
}

4.结语

如上是ARCore渲染背景的流程,背景渲染最主要一点是OES纹理渲染,当然也可以现在内部转成普通纹理。

ARCore背景渲染相关推荐

  1. ARCore深度渲染问题分析

    文章目录 1.前言 2.深度图显示 3.深度遮挡 3.1 处理流程 3.2 相关代码 4.结语 1.前言 ARCore深度效果显示分为两部分:第一部分是深度图显示,另一部分为深度遮挡(即实现真实物体与 ...

  2. HTML/BODY的背景渲染原理

    HTML/BODY的背景渲染原理 一.前言 结论先行: 我们给body设置背景色,实际我们看见的未必是body上的背景色: 当html标签没有设置背景色时,我们看见的是作用在浏览器画布上的背景色,不是 ...

  3. html背景渲染原理(body透明渐变)

    给body设置的背景色 实际上 我们未必看得见: 偶然情况下发现 给body写的背景色 全被浏览器给覆盖了 文中涉及的是CSS中关于特殊元素(html/body)的背景渲染的原理 当html标签没有设 ...

  4. html设置图片切割,HTML+CSS实现合并图片的切割显示以及背景渲染

    今天用了大约3小时才搞定了这么一小点工作.. 合并图片的切割显示是我早就想研究一下的,因为这个东西应用非常广泛,今天总算在HTML的框架里有了些了解. 核心代码为: div标签是个很好的东西,用来逻辑 ...

  5. ARCore之路-技术原理(二)

      前文说过,ARCore 使用三个主要功能将虚拟内容与通过手机摄像头看到的现实世界整合:运动跟踪. 环境理解.光估计.那么我们就来详细说一下这三个方面的原理,然后一并学习一下ARCore带来的新概念 ...

  6. Android AR开发实践之七:OpenGLES相机预览背景绘制源码详解

    Android AR开发实践之七:OpenGLES相机预览背景绘制源码详解 目录 Android AR开发实践之七:OpenGLES相机预览背景绘制源码详解 一.OpenGL ES渲染管线 1.基本处 ...

  7. 关于出版《AR Foundation增强现实开发实战(ARCore版)》(2022-09-15日更新)

       感谢各位读者的支持,书籍目前已上市各大电商平台. ----------- 2022年3月18日创建 ---------   在元宇宙科技浪潮推动下,增强现实(Augmented Reality, ...

  8. live2dmesh渲染优先级_live2dsdk的opengl示例详解

    (第一次写,有错误恳请指正XD) (希望能帮助到感兴趣的小伙伴) (看客别看到这么多代码就想走!! 后面有生成示例:3) 先放张图介绍一下各个类的基本功能 首先进入程序入口 int main(int ...

  9. ExtJS4.1.1 设置表格背景颜色 修改文本颜色 在表格中插入图片

    由于ExtJS版本不断更新,各种渲染方式也随之有所改变,目前大部分书籍还是停留在3版本,对于ExtJS4.1.1版本的表格渲染,设置表格行背景颜色的方式如下: 首先,定义行的样式: 1 .yellow ...

最新文章

  1. 刚刚,中国空间站核心舱“天和”出征太空!
  2. 前端使用 Nginx 反向代理彻底解决跨域问题
  3. clientdataset 过滤 in_天心大风量亚高效过滤器
  4. USTC English Club Note20171016(2)
  5. RuoYi-Cloud 部署篇_02(windows环境 Oracle +nginx版本)
  6. Winhex数据恢复笔记(五)
  7. Python一些常用模块
  8. IDEA阅读spring源码并调试
  9. 深度学习中的优化算法之Adadelta
  10. sip 软电话 java源码,完美的 SIP 软电话
  11. 深度学习与自然语言处理(1)_斯坦福cs224d Lecture 1
  12. 七牛的管理接口不支持js端发送请求进行管理(设计到跨域问题)
  13. 巴拿赫空间的基本概念
  14. 如何购买腾讯云服务器?腾讯云服务器购买教程
  15. 下载游戏apk,并安装
  16. C#,深入浅出全接触
  17. gaussDB200 单节点安装
  18. Internet安全协议 学习笔记
  19. 推荐一个Tkinter GUI 设计神器,不用一行代码就能搞定!
  20. iOS打印当前控制器名称、事件名称

热门文章

  1. C++ 实现命令行画心形代码,有多个爱心代码,简单可调数据和字符,可装X,也可用于浪漫的表白,可实现跳动、保存等功能
  2. 概率论基础 —— 5.离散型二维随机变量
  3. Simscape multibody 移动关节
  4. 鹅厂机器狗花式穿越10m梅花桩:前空翻、单桩跳、起身作揖...全程不打一个趔趄...
  5. 绥化学院2021聋人高考成绩查询,2020聋人高考形势分析
  6. 产品经理必备技能和职责
  7. 【PB】pb打开pbw时提示Attempt to open datawindow failed错误解决办法
  8. wampserver3.1 64下载地址
  9. dnf全部使用_dnf命令_Linux dnf 命令用法详解:新一代的RPM软件包管理器
  10. bigword游戏服务器文档,使用Golang实现万人同服的游戏服务器.pdf