The Lab Renderer学习笔记

前言

Unity Vision VR/AR Summit来到中国了(http://www.bagevent.com/event/197605?bag_track=http://www.bagevent.com/event/197605   ),最近也关注了一下Unity的VR开发。

大概是6月份看到新闻:Steam发布了The Lab所使用的渲染器的所有源代码。我一直挺好奇的,对于Unity3D这样不开源的引擎,如果搞一个渲染器呢?今天有时间读一下代码,一探究竟。

相关链接

- 官方帖子:http://steamcommunity.com/games/250820/announcements/detail/604985915045842668

- GitHub下载:https://github.com/ValveSoftware/the_lab_renderer

- Unity Asset Store下载:https://www.assetstore.unity3d.com/en/#!/content/63141

特性&实现

从GitHub下载了The Lab Renderer之后,粗略的浏览一遍,内容不多,主要是几个组件的C#代码和一些Shader。接下来就看看它的主要特性是怎么实现的。

Single-Pass Forward Rendering

The Lab Renderer使用Forward Rendering的原因主要是为了MSAA(MultiSampling Anti-Aliasing)和效率。然而Unity默认的Forward Rendering使用了Multi-Pass来渲染所有灯光(每个物体的每个动态灯要多一个Pass来渲染它的光照),The Lab Renderer提供了一个单Pass渲染多个灯光的解决方案。

为了实现Single-Pass Forward Rendering,首先要在Player Settings做一些设置,如上图所示。所谓的“Single-Pass”主要靠Shader来实现了。大体思路就是在“vr_lightng.cginc”这个shader文件中定义了一系列灯光参数的数组:

#define MAX_LIGHTS 18
...
float4 g_vLightColor[ MAX_LIGHTS ];
float4 g_vLightPosition_flInvRadius[ MAX_LIGHTS ];
float4 g_vLightDirection[ MAX_LIGHTS ];

然后使用一个for循环,一次性计算所有灯光的光照:

LightingTerms_t ComputeLighting( float3 vPositionWs ...)
{
    [ loop ] for ( int i = 0; i < g_nNumLights; i++ )
    {}
}

接下来就是在C#层来处理灯光信息了。

  • 首先,需要为每个Unity中的灯光对象添加“ValveRealtimeLight.cs ”脚本,class ValveRealtimeLight管理一个静态变量“List< ValveRealtimeLight > s_allLights”用来簿记所有的灯光数据。
  • 然后,需要在Main Camera对象上添加“ValveCamera.cs”脚本。在class ValveCamera.UpdateLightConstants()成员函数中,会计算所有的灯光相关的参数,并设置到Shader的常量中。

    以上就是The Lab Renderer的Single-Pass Forward Rendering这个特性的实现思路。

Shadows

The Lab Renderer还接管了阴影的渲染。需要在Unity的Quality->Shadows settings 中选择“Disable Shadows”来关闭Unity默认的阴影。

如上图所示,The Lab Renderer使用Shadow Mapping的算法来生成实时阴影。这个算法粗略的过程是这样的:

  1. 从灯光的角度渲染一个深度缓冲。这个深度缓冲的几何意义,可以粗略的理解为每个像素点到灯光最近的距离;这个深度缓冲又被成为Shadow Buffer或者Shadow Map。
  2. 在渲染Back Buffer的时候,对于每个需要着色的点,将其“投影”(Projection)到上述的Shadow Map空间,然后进行比较,来判断这个点是不是离灯光最近—-也就是有没有被其他物体遮挡,即在阴影之中。
  3. 生成Shadow Buffer的渲染,对于Spot Light非常直观啦;对于方向光,The Lab采用了近似的方法:将方向光替换成一个“非常远”的点光源;对于点光源,The Lab使用6个假的Spot Light来替代。0_0|||

上述算法的流程控制,在ValveCamera.cs脚本中实现。首先它需要一个从灯光角度渲染的Camera、一个RenderTexture用做Shadow Map,还需要一个Shader来进行Shadow Map渲染(Resources/vr_cast_shadows.shader)。

[ExecuteInEditMode]
[RequireComponent( typeof( Camera ) )]
public class ValveCamera : MonoBehaviour
{
    ...
    [NonSerialized] private Camera m_shadowCamera = null;
    [NonSerialized] public RenderTexture m_shadowDepthTexture = null;
    [NonSerialized] public Shader m_shaderCastShadows = null;
    ...
}

在ValueCamera.OnPreCull()脚本回调函数中会调用ValueCamera.ValveShadowBufferRender()来渲染Shadow Buffer。如上图的Shadow所示,The Lab把所有灯光渲染到了一个整体的Shadow Buffer之中,把每个灯光Shadow Buffer对应的区域,存储到Shader参数“g_vShadowMinMaxUv”之中。这样在前面讲的Single-Pass Forward Rendering过程中,就可以在一个Pass实现所有灯光的光影计算了。

至于vr_cast_shadows.shader的内容,就很简单了,它核心就是一个Vertex Shader,用来计算Projection之后的Position坐标就好,UV啊什么之类的都可以省略掉了。

在灯光渲染的Shader中(vr_lighting.cginc)通过ComputeShadow_PCF_3x3_Gaussian()函数来计算阴影。所谓的PCF就是Percentage Closer Filter,为的是产生阴影的边缘柔滑效果。在这个函数中,它才算有了高斯过滤来对目标点周围的3x3范围进行计算。

Adaptive Quality

对于VR来说,帧速率是非常重要的,所以Valve的大牛就添加了这个特性:动态调节渲染质量,达到稳定的搞效率,这是他在GDC 2016上的一个演讲:https://www.youtube.com/watch?v=eIlb688pUu4

这部分主要涉及到何时去调节质量,调节哪些地方(哪些是不能随便调的),具体的逻辑都在ValveCamera.UpdateAdaptiveQuality()这个函数里了。

时间: 2024-10-27 12:36:30

The Lab Renderer学习笔记的相关文章

MIT 6.828 JOS学习笔记2. Lab 1 Part 1.2: The kernel

Lab 1 Part 1: PC bootstrap 我们继续~ PC机的物理地址空间 这一节我们将深入的探究到底PC是如何启动的.首先我们看一下通常一个PC的物理地址空间是如何布局的:                           这张图仅仅展示了内存空间的一部分. 第一代PC处理器是16位字长的Intel 8088处理器,这类处理器只能访问1MB的地址空间,即0x00000000~0x000FFFFF.但是这1MB也不是用户都能利用到的,只有低640KB(0x00000000~0x00

2016年7月19日学习笔记

2016年7月19日学习笔记 计算机系统的组成部分 计算机系统由硬件系统和软件系统两大部分组成 硬件系统 冯.诺依曼体系结构: 1946年数学家冯.诺依曼提出运算器,控制器,存储器,输入设备,输出设备. 具体变现为一下硬件: 运算器,控制器  ------>  CPU 存储器          ------>  内存(断电数据清空),硬盘(可永久存储数据) 输入设备------>  键盘,鼠标等 输出设备------>  显示器 打印机等 软件系统 OS : Operating S

R语言学习笔记

參考:W.N. Venables, D.M. Smith and the R DCT: Introduction to R -- Notes on R: A Programming Environment for Data Analysis and Graphics,2003. http://bayes.math.montana.edu/Rweb/Rnotes/R.html 前言:关于R 在R的官方教程里是这么给R下注解的:一个数据分析和图形显示的程序设计环境(A system for data

ArcGIS API for JavaScript 4.2学习笔记[0] AJS4.2概述、新特性、未来产品线计划与AJS笔记目录

放着好好的成熟的AJS 3.19不学,为什么要去碰乳臭未干的AJS 4.2? 诸君,我喜欢嫩的--呸呸呸 诸君,我喜欢3D咋了?新事物会替代旧事物不是~ ArcGIS API for JavaScript 4.2概述 AJS 4.2,即ArcGIS API for JavaScript 4.2,是美国ESRI公司针对WebGIS市场推出的.利用JavaScript和Dojo开发的一款产品,它在2016年12月发布.而AJS 4.0 beta则在一年前就发布了. 关于AJS3和AJS4选择的问题,

WEBGL学习笔记(七):实践练手1-飞行类小游戏之游戏控制

接上一节,游戏控制首先要解决的就是碰撞检测了 这里用到了学习笔记(三)射线检测的内容了 以鸟为射线原点,向前.上.下分别发射3个射线,射线的长度较短大概为10~30. 根据上一节场景的建设,我把y轴设为前进方向,z轴设为高度~ 如果射线返回有结果,那么说明鸟遇到了障碍物.代码如下: var raycaster1 = new THREE.Raycaster(birdmesh.position, new THREE.Vector3(0, 1, 0), 0, 30) var raycaster2 =

【Unity Shaders】学习笔记——SurfaceShader(九)Cubemap

[Unity Shaders]学习笔记——SurfaceShader(九)Cubemap 如果你想从零开始学习Unity Shader,那么你可以看看本系列的文章入门,你只需要稍微有点编程的概念就可以. 水平有限,难免有谬误之处,望指出. 上一节中讲述了制作Cubemap的方法.这一节讲讲怎么使用它. Simple Cubemap 先来看一下最简单的Cubemap. Shader "Custom/SimpleReflection" { Properties { _MainTint (&

【Unity 3D】学习笔记四十三:布料

布料 布料是特殊的组件,它可以变化成任意形状,比如说:随风飘的旗子,窗帘等 创建布料的方法有两种:创建布料对象,在游戏对象中添加布料组件.前者通过hierarchy视图中选择create--cloth即可,创建后,系统会自动将互动布料组件(interactive clothe)与布料渲染组件(cloth renderer)添加值该对象中.后者是在导航菜单中选component--physics--interactive cloth菜单项即可. 交互布料组件是由网格组成的布料,只要用于布料的逻辑判

【Unity 3D】学习笔记四十四:路径渲染

路径渲染 路径渲染属于特效渲染组件,用于跟随运动中的游戏对象.首先在hierarchy视图中,创建一个球体.然后在菜单导航栏中选择component--effects--trial renderer即可将路径渲染组件添加至该球体对象中. cast shadows:显示阴影效果. receive shadows:接受阴影效果. materials:材质. size:渲染的材质数量,可添加或删除. element 0:渲染材质文件. use light probes:是否使用光线探头. light

Cocos2d-x 3.1.1 学习笔记(三)学习绘图API

关于cocos2d-x 3.1.1 版本的绘图方法有两种 1.使用DrawNode类绘制自定义图形. 2.继承Layer类重写draw()方法. 以上两种方法都可以绘制自定义图形,根据自己的需要选择合适的方法. 一.使用DrawNode类绘制自定义图形 使用DrawNode 类绘制图形是最简单的方法,create一个DrawNode类,然后添加进场景.然后就可以愉快的绘图了. 1 auto s = Director::getInstance()->getWinSize(); 2 //创建 3 a