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. js与cookie的domain和path之间的关系

    1.前言 使用javascript操作cookie我们都经常使用,对cookie不是很了解的话可以看下这篇帖子[javascript操作cookie](http://www.cnblogs.com/D ...

  2. Request Tracker 4.0.13 发布

    Request Tracker 4.0.13 修复了几个重要的安全问题. Request Tracker,企业级的问题跟踪系统

  3. elixir 高可用系列(二) GenServer

    概述 如果我们需要管理多个进程,那么,就需要一个专门的 server 来集中监控和控制这些进程的状态,启停等. OTP 平台中的 GenServer 就是对这个 server 通用部分的抽象. 利用 ...

  4. ASP.NET MVC5 与EF6学习系列

    最近学习使用MVC5和EF6,博客园搜索了一番,写下这篇文章记录,以便学习使用. 一.ASP.NET MVC5 网站开发 @洞庭夕照写的博客系列 ASP.NET MVC5 网站开发实践 - 概述 AS ...

  5. ASP.NET WEB API 中的路由调试与执行过程跟踪

    路由调试 RouteDebugger 是调试 ASP.NET MVC 路由的一个好的工具,在ASP.NET WEB API中相应的有 WebApiRouteDebugger ,Nuget安装 Inst ...

  6. 设计模式之美:Adapter(适配器)

    索引 别名 意图 结构 参与者 适用性 效果 相关模式 实现 实现方式(一):简单直接的对象适配器. 实现方式(二):实现双向类适配器. 别名 包装器(Wrapper) 意图 将一个类的接口转换成客户 ...

  7. unity3D——自带寻路Navmesh入门教程(二)(转)

    转自:http://liweizhaolili.blog.163.com/blog/static/16230744201271210237616/ 上一节简单介绍了NavMesh寻路的基本用法,这次来 ...

  8. UEditor编辑器上传图片开发流程

    在ueditor目录下找到uedior.config.js,找到如下三行: ,imageUrl: "<%=path %>/controller.json" //图片上传 ...

  9. 浅谈sql中的in与not in,exists与not exists的区别

    转 浅谈sql中的in与not in,exists与not exists的区别   12月12日北京OSC源创会 —— 开源技术的年终盛典 »   sql exists in 1.in和exists ...

  10. paip.jdbc 连接自动释放的测试

    paip.jdbc 连接自动释放的测试 使用的mysql jdbc3.1.6  以及5.1.7 测试结果,在没有conn.close()的情况哈.. 作者Attilax  艾龙,  EMAIL:146 ...