render学习

Posted 131362wsc

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了render学习相关的知识,希望对你有一定的参考价值。

一.前言

1.vue程序的运行过程:模板 -> 进行编译 -> 生成ast树 -> 数据绑定 -> 生成render函数 -> 成虚拟dom树 -> 真实dom树

  • 模板:Vue的模板基于纯HTML,基于Vue的模板语法,我们可以比较方便地声明数据和UI的关系。

  • AST:AST是Abstract Syntax Tree的简称,俗称‘抽象语法树’它是一种数据结构。是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。

  • 渲染函数:渲染函数是用来生成Virtual DOM的。Vue推荐使用模板来构建我们的应用界面,在底层实现中Vue会将模板编译成渲染函数,当然我们也可以不写模板,直接写渲染函数,以获得更好的控制 (这部分是我们今天主要要了解和学习的部分)。

  • Dom树:当浏览器读到HTML代码时,它会建立一个DOM节点树来保持追踪,如果你会画一张家谱树来追踪家庭成员的发展一样。每个元素都是一个节点。每片文字也是一个节点。甚至注释也都是节点。一个节点就是页面的一个部分。就像家谱树一样,每个节点都可以有孩子节点 (也就是说每个部分可以包含其它的一些部分)。

  • Virtual DOM:虚拟DOM树就是为了解决浏览器性能问题而被设计出来的,其实就是一个普通的js对象,它是用来描述一段HTML片段的。当页面发生改变Vue会再创建一颗新的虚拟DOM树,前后两颗新旧虚拟DOM树进行对比,Vue通过diff算法,去记录差异的地方将有差异的地方更新到真实的DOM树中,可以大大缩短响应的时间。

综上:

(1)如果直接使用render函数,就省略了模板的编译过程,vue运行的更快。

(2)Vue的编译器在编译模板之后,会把这些模板编译成一个渲染函数。而函数被调用的时候就会渲染并且返回一个虚拟DOM的树。

2.数据更新机制

每个Vue组件都有一个对应的watcher,这个watcher将会在组件render的时候收集组件所依赖的数据(比如data中定义的那些),当依赖有更新的时候,Vue自身的响应式系统就会监听到数据的变化,就会重新渲染(也就是从头重新执行一遍直到render函数走完),当重新进行渲染之后,会生成一个新的虚拟树,将新的树与旧的树进行对比,就可以最终得出应施加到真实DOM上的改动。

二.Render函数

1.使用场景render 函数(渲染函数 跟 template 一样都是创建 html 模板的,但是有些场景中用 template 实现起来代码冗长繁琐而且有大量重复,这时候就可以用 render 函数

2.render函数介绍

render函数的返回值:VNode(即:虚拟节点),也就是我们要渲染的节点。

render 函数的参数createElement 是 render 函数 的参数,它本身也是个函数,并且有三个参数如下。

createElement(参数1,参数2,参数3); 

参数1:想渲染的html标签名或者组件名不区分大小写,用引号括起来,例如:\'div\',\'span\',。---必填

参数2:该dom节点的配置的数据对象,如id,class,style,事件等(具体请参考文档【深入数据对象】的描述)。---非必填

参数3:是一个数组,数组里面存放子元素。若还要创建子元素,则可以在数组中继续写createElement函数。---非必填

(有关createElement具体使用,例如添加事件监听,如何使用插槽等,都可参考Vue官方文档)

3.具体用法

(1)用法一:基本使用场景,也就是render函数中只传入一个参数-createElement。

格式为:render: function (createElement)

实例如:见代码

引入jsx插件的写法(需要安装一个插件,写起来更接近template中的代码):

(2)用法二:render函数传入两个参数------(见官方文档中【函数式组件】的描述)

格式为:render: function (createElement, context)

其中context是一个对象,组件需要的一切都是通过它来传递的。 

The Lab Renderer学习笔记

The Lab Renderer

前言

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

UnityVRSummit

大概是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渲染多个灯光的解决方案。

TheLab-PlayerSettings

为了实现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默认的阴影。

TheLab-ShadowMap

如上图所示,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()这个函数里了。

以上是关于render学习的主要内容,如果未能解决你的问题,请参考以下文章

Vue学习笔记进阶篇——Render函数

react学习(71)--render使用

自顶而下学习react源码 架构篇 render阶段

render学习

react学习----react转换值同render

react学习----通过设置初始值控制页面render渲染