The Lab Renderer for Unity是Valve针对VR在Unity的体验渲染器,提高VR的渲染效率,更多的大家可以查相应资料,在这,说个The Lab Renderer for Unity现阶段的问题,可能是第一版,在地形并不能接受Valve渲染产生的阴影,对应地形上的树啥的也不能产生阴影,经过相应修改后,如下是改动后的效果图。  

  

  我们首先需要分析下Lab Renderer的基本渲染流程,主要代码在ValveCamera中,可以看到,渲染流程还是很简单的,相应的Lab Renderer文档也首先点明了,前向单通道渲染。

  我们知道在以前如Ogre2.0以前的前向渲染时,如果有多个灯光,是需要多次PASS来叠加光源得到效果,嗯,Unity本身也是这样处理的,这样灯光越多,灯光与模型就是L*M的关系,所以大家开始采用后向渲染,把模型相应数据渲染到GBuffer中,然后与光源计算得到正确显示,只需要L+M,虽然延迟渲染解决了多光源的问题,但是如下透明度,硬件AA,复杂材质,大量带宽是延迟渲染比较难搞的部分。

  而在VR中,延迟渲染前没有比较好用的空间AA算法,一般来说在VR中,采用后向抗锯齿算法,一些UI还有字体还是还看到锯齿,而VR眼睛分辨率比主机高的多,GBuffer你搞低了效果不好,大一点,双摄像头需要的显存带宽更是比主机多了去,所以当你导入Stream VR的包时,都会让你选择前向渲染,嗯,前向渲染的问题前面说了,多光源,而ValveCamera主要就是来解决如何在前向渲染里的单Pass里渲染多个光源的。

  Lab Renderer会要求你在每个实时光源下挂一个ValveRealtimeLight脚本,这个脚本主要是收集所有实时光源,然后在渲染时做二件事情,都是在OnPreCull之前,一是生成光源阴影图(RenderShadowBuffer),二是把所有灯光的信息填入到vr_lighting.cginc中的ValveVrLighting的const buffer中。

  在以每个光源位置与方向来渲染当前的模型来生成阴影,不同类型光源会有些不同,如方向光,位置移到老后面,FOV也需要调整,肯定要保证所有模型都渲染到,而Point光源,需要渲染六个面,只有spot光源,其属性与Camera对应,不需要啥特殊处理,渲染的RenderTarget只需要一个差不多类似深度的值就行了,所有RenderTarget全在m_shadowDepthTexture中,根据在每个ValveRealtimeLight脚本中设置的大小自动选择一个位置,注意在场景中的任何地方不能有摄像机视野内的所有光源的ValveRealtimeLight设置的大小加起来不能超过m_shadowDepthTexture本身的大小。

  然后就是写入所有灯光的信息到ValveVrLighting的const buffer中,在UpdateLightConstants这个方法中,其实这个过程和Ogre2.1的灯光处理很类似,大家可以看我以前写的 Ogre2.1 灯光与阴影,当然Ogre2.1会复杂的多,采用的是Forward+,会把屏幕分成N多小格,每个小格确定受到那些光源的影响,不过思路确实有很多是一样的。

  明白了Lab Renderer做了啥,我们才开始做最主要的部分,替换地形着色器的代码,使之采用上面的m_shadowDepthTexture来产生阴影,并去掉原来的光照计算,采用Lab Renderer的光照算法,注意在这,我们还是想要能够使用Unity本身的地形编辑器,所以我们并不是简单把地形着色器有材质改成使用Custom,我们需要替换他本身的Standard地形着色器代码,在Unity5以后,对应shader文件为Standard-FirstPass.shader,我们要做的就是,把Standard-FirstPass.shader与vr_standard.shader终合起来,地形表面的颜色采用的Standard-FirstPass.shader里的SplatmapMix方法,而阴影以及光源影响在vr_standard.shader中的ComputeLighting方法。

  需要注意的,Standard-FirstPass.shader本身做为SurfaceShader,提供的Input并不满足我们ComputeLighting想要的参数,所以我们需要先看下Standard-FirstPass.shader生成完整的,包含顶点,片断着色器的代码,如下最下面的按钮:

  

  注意,产生的文件会有很多Pass,如每种Fog对应不同的Pass,在这我们只需要一个Pass就够了,其中Fog也让Lab Renderer里的vr_standard.shader中的处理方法来处理。

  我们根据vr_standard.shader开始改造我们选择的一个Pass,首先我们要确认vr_standard.shader有那些预处理定义与相应操作是我们根本不需要的,或者是在地形中默认处理方式,可以简化大部分vr_standard.shader片断着色器中的代码,移除Standard-FirstPass.shader大部分片断着色器代码,添加vr_standard.shader片断着色器的代码,如前面所说,处理好Standard-FirstPass.shader里的SplatmapMix方法与vr_standard.shader中的ComputeLighting方法就成功了99%。如下是处理后的版本,还有Fog这边没有测试,大家自己去改,不麻烦。

  文件链接:vr_terrain.zip

Shader "Nature/Terrain/Standard" {
Properties{
// set by terrain engine
[HideInInspector] _Control("Control (RGBA)", 2D) = "red" {}
[HideInInspector] _Splat3("Layer 3 (A)", 2D) = "white" {}
[HideInInspector] _Splat2("Layer 2 (B)", 2D) = "white" {}
[HideInInspector] _Splat1("Layer 1 (G)", 2D) = "white" {}
[HideInInspector] _Splat0("Layer 0 (R)", 2D) = "white" {}
[HideInInspector] _Normal3("Normal 3 (A)", 2D) = "bump" {}
[HideInInspector] _Normal2("Normal 2 (B)", 2D) = "bump" {}
[HideInInspector] _Normal1("Normal 1 (G)", 2D) = "bump" {}
[HideInInspector] _Normal0("Normal 0 (R)", 2D) = "bump" {}
[HideInInspector][Gamma] _Metallic0("Metallic 0", Range(0.0, 1.0)) = 0.0
[HideInInspector][Gamma] _Metallic1("Metallic 1", Range(0.0, 1.0)) = 0.0
[HideInInspector][Gamma] _Metallic2("Metallic 2", Range(0.0, 1.0)) = 0.0
[HideInInspector][Gamma] _Metallic3("Metallic 3", Range(0.0, 1.0)) = 0.0
[HideInInspector] _Smoothness0("Smoothness 0", Range(0.0, 1.0)) = 1.0
[HideInInspector] _Smoothness1("Smoothness 1", Range(0.0, 1.0)) = 1.0
[HideInInspector] _Smoothness2("Smoothness 2", Range(0.0, 1.0)) = 1.0
[HideInInspector] _Smoothness3("Smoothness 3", Range(0.0, 1.0)) = 1.0 // used in fallback on old cards & base map
[HideInInspector] _MainTex("BaseMap (RGB)", 2D) = "white" {}
[HideInInspector] _Color("Main Color", Color) = (,,,)
} SubShader{
Tags{
"Queue" = "Geometry-100"
"RenderType" = "Opaque"
"PerformanceChecks" = "False"
} Pass
{
Name "FORWARD"
Tags{ "LightMode" = "ForwardBase" "PassFlags" = "OnlyDirectional" } // NOTE: "OnlyDirectional" prevents Unity from baking dynamic lights into SH terms at runtime CGPROGRAM
#pragma target 5.0
#pragma only_renderers d3d11
#pragma exclude_renderers gles
#pragma vertex MainVs
#pragma fragment MainPs
#pragma shader_feature S_RECEIVE_SHADOWS
#pragma multi_compile _ D_VALVE_SHADOWING_POINT_LIGHTS
#pragma shader_feature S_OVERRIDE_LIGHTMAP
#pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON
#pragma multi_compile DIRLIGHTMAP_OFF DIRLIGHTMAP_COMBINED DIRLIGHTMAP_SEPARATE
#pragma multi_compile DYNAMICLIGHTMAP_OFF DYNAMICLIGHTMAP_ON
// Includes -------------------------------------------------------------------------------------------------------------------------------------------------
#include "UnityCG.cginc"
#include "UnityLightingCommon.cginc"
#include "UnityStandardUtils.cginc"
#include "UnityStandardInput.cginc" #define S_RECEIVE_SHADOWS 1
#define D_VALVE_SHADOWING_POINT_LIGHTS 1
#include "Lighting.cginc" #pragma multi_compile __ _TERRAIN_NORMAL_MAP
#define TERRAIN_STANDARD_SHADER
#define TERRAIN_SURFACE_OUTPUT SurfaceOutputStandard
#include "TerrainSplatmapCommon.cginc"
#include "vr_utils.cginc"
#include "vr_lighting.cginc"
#include "vr_matrix_palette_skinning.cginc"
#include "vr_fog.cginc" #define LIGHTMAP_ON 1
#define DYNAMICLIGHTMAP_ON 1
#define DYNAMICLIGHTMAP_OFF 0
#define DIRLIGHTMAP_COMBINED 1
#define S_OVERRIDE_LIGHTMAP 0 half _Metallic0;
half _Metallic1;
half _Metallic2;
half _Metallic3; half _Smoothness0;
half _Smoothness1;
half _Smoothness2;
half _Smoothness3; // Structs --------------------------------------------------------------------------------------------------------------------------------------------------
struct VS_INPUT
{
float4 vPositionOs : POSITION;
float3 vNormalOs : NORMAL;
float2 vTexCoord0 : TEXCOORD0;
float2 vTexCoord1 : TEXCOORD1;
#if ( DYNAMICLIGHTMAP_ON || UNITY_PASS_META )
float2 vTexCoord2 : TEXCOORD2;
#endif
}; struct PS_INPUT
{
float4 vPositionPs : SV_Position;
float3 vPositionWs : TEXCOORD0;
float3 vNormalWs : TEXCOORD1;
float2 vTextureCoords : TEXCOORD2;
float4 vLightmapUV : TEXCOORD3;
float2 vFogCoords : TEXCOORD4;
float4 pack0 : TEXCOORD5; // _Splat0 _Splat1
float4 pack1 : TEXCOORD6; // _Splat2 _Splat3
float2 custompack0 : TEXCOORD7; // tc_Control
}; float g_flValveGlobalVertexScale = 1.0; // Used to "hide" all valve materials for debugging // World-aligned texture
float3 g_vWorldAlignedTextureSize = float3(1.0, 1.0, 1.0);
float3 g_vWorldAlignedNormalTangentU = float3(-1.0, 0.0, 0.0);
float3 g_vWorldAlignedNormalTangentV = float3(0.0, 0.0, 1.0);
float3 g_vWorldAlignedTexturePosition = float3(0.0, 0.0, 0.0); float4 _Splat0_ST;
float4 _Splat1_ST;
float4 _Splat2_ST;
float4 _Splat3_ST;
// MainVs ---------------------------------------------------------------------------------------------------------------------------------------------------
PS_INPUT MainVs(appdata_full i)
{
PS_INPUT o = (PS_INPUT); UNITY_SETUP_INSTANCE_ID(i);
UNITY_TRANSFER_INSTANCE_ID(v, o);
Input customInputData;
SplatmapVert(i, customInputData);
o.custompack0.xy = customInputData.tc_Control; float3 vPositionWs = mul(unity_ObjectToWorld, i.vertex).xyz;
o.vPositionWs.xyz = vPositionWs.xyz;
o.vPositionPs.xyzw = mul(UNITY_MATRIX_MVP, i.vertex.xyzw); // Normal
float3 vNormalWs = UnityObjectToWorldNormal(i.normal);
o.vNormalWs.xyz = vNormalWs.xyz;
#if ( LIGHTMAP_ON )
o.vLightmapUV.xy = i.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
#endif #if ( DYNAMICLIGHTMAP_ON )
o.vLightmapUV.zw = i.texcoord2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
#endif o.vFogCoords.xy = CalculateFogCoords(vPositionWs.xyz); o.pack0.xy = TRANSFORM_TEX(i.texcoord, _Splat0);
o.pack0.zw = TRANSFORM_TEX(i.texcoord, _Splat1);
o.pack1.xy = TRANSFORM_TEX(i.texcoord, _Splat2);
o.pack1.zw = TRANSFORM_TEX(i.texcoord, _Splat3);
return o;
} // MainPs ---------------------------------------------------------------------------------------------------------------------------------------------------
struct PS_OUTPUT
{
float4 vColor : SV_Target0;
}; PS_OUTPUT MainPs(PS_INPUT i)
{
PS_OUTPUT po = (PS_OUTPUT); Input surfIN;
UNITY_INITIALIZE_OUTPUT(Input, surfIN);
surfIN.uv_Splat0.x = 1.0;
surfIN.uv_Splat1.x = 1.0;
surfIN.uv_Splat2.x = 1.0;
surfIN.uv_Splat3.x = 1.0;
surfIN.tc_Control.x = 1.0;
surfIN.uv_Splat0 = i.pack0.xy;
surfIN.uv_Splat1 = i.pack0.zw;
surfIN.uv_Splat2 = i.pack1.xy;
surfIN.uv_Splat3 = i.pack1.zw;
surfIN.tc_Control = i.custompack0.xy; half4 splat_control;
half weight;
fixed4 mixedDiffuse;
half4 defaultSmoothness = half4(_Smoothness0, _Smoothness1, _Smoothness2, _Smoothness3);
SplatmapMix(surfIN, defaultSmoothness, splat_control, weight, mixedDiffuse, i.vNormalWs);
//mixedDiffuse.rgb;weight;mixedDiffuse.a;dot(splat_control, half4(_Metallic0, _Metallic1, _Metallic2, _Metallic3)); float3 vAlbedo = mixedDiffuse.rgb; float3 vTangentUWs = float3(1.0, 0.0, 0.0);
float3 vTangentVWs = float3(0.0, 1.0, 0.0);
float3 vGeometricNormalWs = float3(0.0, 0.0, 1.0);
i.vNormalWs.xyz = normalize(i.vNormalWs.xyz);
vGeometricNormalWs.xyz = i.vNormalWs.xyz;
float3 vNormalWs = vGeometricNormalWs.xyz;
float3 vNormalTs = float3(0.0, 0.0, 1.0); // Roughness //
float2 vRoughness = float2(0.6, 0.6);
// Reflectance and gloss
float3 vReflectance = float3(0.0, 0.0, 0.0);
float flGloss = 0.0;
vRoughness.xy = (1.0 - flGloss).xx; LightingTerms_t lightingTerms;
lightingTerms.vDiffuse.rgb = float3(1.0, 1.0, 1.0);
lightingTerms.vSpecular.rgb = float3(0.0, 0.0, 0.0);
lightingTerms.vIndirectDiffuse.rgb = float3(0.0, 0.0, 0.0);
lightingTerms.vIndirectSpecular.rgb = float3(0.0, 0.0, 0.0);
lightingTerms.vTransmissiveSunlight.rgb = float3(0.0, 0.0, 0.0); float flFresnelExponent = 5.0;
float flMetalness = 0.2f; float4 vLightmapUV = float4(0.0, 0.0, 0.0, 0.0);
#if (LIGHTMAP_ON || DYNAMICLIGHTMAP_ON )
vLightmapUV.xy = i.vLightmapUV.xy;
#if ( DYNAMICLIGHTMAP_ON )
vLightmapUV.zw = i.vLightmapUV.zw;
#endif
// Compute lighting
lightingTerms = ComputeLighting(i.vPositionWs.xyz, vNormalWs.xyz, vTangentUWs.xyz, vTangentVWs.xyz, vRoughness.xy, vReflectance.rgb, flFresnelExponent, vLightmapUV.xyzw); #if ( S_OCCLUSION )
float flOcclusion = tex2D(_OcclusionMap, i.vTextureCoords.xy).g;
lightingTerms.vDiffuse.rgb *= LerpOneTo(flOcclusion, _OcclusionStrength * _OcclusionStrengthDirectDiffuse);
lightingTerms.vSpecular.rgb *= LerpOneTo(flOcclusion, _OcclusionStrength * _OcclusionStrengthDirectSpecular);
lightingTerms.vIndirectDiffuse.rgb *= LerpOneTo(flOcclusion, _OcclusionStrength * _OcclusionStrengthIndirectDiffuse);
lightingTerms.vIndirectSpecular.rgb *= LerpOneTo(flOcclusion, _OcclusionStrength * _OcclusionStrengthIndirectSpecular);
#endif
#endif // Diffuse
po.vColor.rgb = (lightingTerms.vDiffuse.rgb + lightingTerms.vIndirectDiffuse.rgb) * vAlbedo.rgb; po.vColor.rgb += lightingTerms.vIndirectSpecular.rgb; // Indirect specular applies its own fresnel in the forward lighting header file //po.vColor.rgb = lightingTerms.vDiffuse.rgb;
po.vColor.a = mixedDiffuse.a; // Emission - Unity just adds the emissive term at the end instead of adding it to the diffuse lighting term. Artists may want both options.
//float3 vEmission = Emission(i.vTextureCoords.xy);
//po.vColor.rgb += vEmission.rgb;
//o.vColor.rgb = ApplyFog(o.vColor.rgb, i.vFogCoords.xy, _FogMultiplier);
// Dither to fix banding artifacts
//po.vColor.rgb = ScreenSpaceDither(i.vPositionPs.xy); return po;
}
ENDCG
} }
Fallback "Nature/Terrain/Diffuse"
}

Nature/Terrain/Standard

  地形中的树开始很奇怪,为啥没有投射阴影,在RenderShadowBuffer时调用m_shadowCamera.RenderWithShader时,在Frame Debug中发现并没有把树加进来,后面把渲染树的shader找到看了下,发现RenderType都不是Opaque,那么一是改变相应树的shader,使RenderType为Opaque,二是直接在RenderWithShader第二个参数填string.Empty就行,这样会有一个问题,会把啥透明的都渲染进来。

  其中vr_standard.shader与Standard-FirstPass.shader针对地形的混合,只是能看到阴影,如果想用,肯定还是要针对性的修改才行。

给The Lab Renderer for Unity中地形添加阴影的更多相关文章

  1. GJM : 【技术干货】给The Lab Renderer for Unity中地形添加阴影

    感谢您的阅读.喜欢的.有用的就请大哥大嫂们高抬贵手"推荐一下"吧!你的精神支持是博主强大的写作动力以及转载收藏动力.欢迎转载! 版权声明:本文原创发表于 [请点击连接前往] ,未经 ...

  2. 关于Unity中地形的创建

    地形创建 Raw图片格式是Unity可以导出的图片格式 Unity很强大,可以直接使用psd文件 地形创建实例 1.创建Unity工程和文件目录1:创建一个地形Terrain: GameObject- ...

  3. 【unity shaders】:Unity中的Shader及其基本框架

    shader和Material的基本关系 Shader(着色器)实际上就是一小段程序,它负责将输入的Mesh(网格)以指定的方式和输入的贴图或者颜色等组合作用,然后输出.绘图单元可以依据这个输出来将图 ...

  4. Unity中Mesh分解与边缘高亮加上深度检测

    一个比较简单的需求,不过遇到些坑,记录下. 房间有多个模型,每个模型可能多个SubMesh,点击后,需要能具体到是那个SubMesh,并且在这个SubMesh上显示边缘高光,以及能个性这单个SubMe ...

  5. 【《Effective C#》提炼总结】提高Unity中C#代码质量的21条准则

    作者:Williammao, 腾讯移动客户端开发工程师 商业转载请联系腾讯WeTest获得授权,非商业转载请注明出处. 原文链接:http://wetest.qq.com/lab/view/290.h ...

  6. Unity中的GC以及优化

    [简介] 常见的 Unity GC 知识点总结出来的思维导图 Unity 官方文档,正巧在博客园发现了已经有位大神(zblade)把原文翻译出来了,而且质量很高~,译文地址 在这里.下面我就可耻地把译 ...

  7. 骨骼动画的原理及在Unity中的使用

    制作骨骼动画 我们看看这几步操作后,我们得到了那些数据: 1.每个皮肤顶点的初始世界坐标. 2.每个骨骼关节顶点的初始世界坐标. 3.每个顶点被骨骼顶点的影响信息. 4.骨骼如何移动. 骨骼动画原理 ...

  8. Unity中的内存泄漏

    在对内存泄漏有一个基本印象之后,我们再来看一下在特定环境——Unity下的内存泄漏.大家都知道,游戏程序由代码和资源两部分组成,Unity下的内存泄漏也主要分为代码侧的泄漏和资源侧的泄漏,当然,资源侧 ...

  9. 浅谈Unity中的GC以及优化

    介绍: 在游戏运行的时候,数据主要存储在内存中,当游戏的数据不在需要的时候,存储当前数据的内存就可以被回收再次使用.内存垃圾是指当前废弃数据所占用的内存,垃圾回收(GC)是指将废弃的内存重新回收再次使 ...

随机推荐

  1. (原创)即使最可怕的自然力量,也不失美丽——火山喷发(摄影,欣赏)

    文中图片摘自腾讯文化:www.cal.qq.com 1.Abstract     最可怕的力量也潜含着最美丽的风景奇观,虽然不能亲眼目睹,但透过大师的视角,一样也能体会到自然力量撼动的美丽. 2.Co ...

  2. SQLSERVER 2012之AlwaysOn -- 一次硬件升级引发的问题

    这是上周遇到的一个案例:对已有的硬件进行升级而引发的问题,期间还触发了一个比较严重的BUG,可谓多灾多难:不过值得庆幸的是,在一连串连锁问题出现的时候,并没有出现人工操作失误(这往往是在处理故障中风险 ...

  3. 设计模式->观察者模式

    观察者模式能非常大的减少模块之前的耦合.具体的观察者模式,客官们可以去看<设计模式>或者<Head first设计模式>等之类的书. 在java中,java.util库中封装了 ...

  4. Dynamic CRM 2013学习笔记(十一)利用Javascript实现子表合计(汇总,求和)功能

    我们经常有这样一种需求,子表里新加或修改一数值后,要马上在主表里把它们的和显示在主表上.如果用插件来实现,可以实现求和,但页面上还要刷新一下才能显示正确.这时就考虑到用JS来实现这一功能,并自动刷新页 ...

  5. 基于Criminisi算法的栅格影像数据敏感地物隐藏

    栅格影像数据敏感地物伪装是指通过计算机智能识别与计算,将影像数据中的敏感地物进行识别与提取,将敏感地物智能替换成公共地物,如草地.森林.湖泊.公园等.但目前该技术并不成熟,同时栅格影像数据敏感地物伪装 ...

  6. python __del__

    python __del__ 转自:http://blog.csdn.net/bbdxf/article/details/25774763 最近学习<Python参考手册>学到Class部 ...

  7. JavaScript 中的 this ,看着一篇就够了

    tip 在 js 中,this 这个上下文总是变化莫测,很多时候出现 bug 总是一头雾水,其实,只要分清楚不同的情况下如何执行就 ok 了. 全局执行 首先,我们在全局环境中看看它的 this 是什 ...

  8. Atitit.人力资源管理原理与概论

    Atitit.人力资源管理原理与概论 1. 人力资源管理 第一章 人力资源管理概述 第二章 人力资源理论基础与发展演变 第三章 人力资源规划 第四章工作分析与工作设计 第五章 员工招聘与录用 第六章 ...

  9. atitit.spring3 mvc url配置最佳实践

    atitit.spring3 mvc url配置最佳实践 1. Url-pattern  bp 1 2. 通用星号url pattern的问题 1 3. Other code 1 4. 参考 2 1. ...

  10. Sql Server2005恢复备份数据库问题-Error:3154 3219

    解决办法: 1.新建一个同名数据库New_HeasySchoolDB2.执行下面的sql语句: restore database New_HeasySchoolDB from disk = 'D:/N ...