Unity 渲染教程(十五)::延迟光源

本文详细介绍了在Unity中自定义延迟渲染光源着色器的过程,包括从创建基本的黑色覆盖着色器开始,逐步添加G缓冲区采样、世界位置计算、光照计算、阴影处理等,最终实现对方向光源、聚光光源和点光源的支持。通过自定义着色器,可以更好地理解和控制游戏中的光照效果。
摘要由CSDN通过智能技术生成

光源的着色器

我们在《渲染13:延迟渲染》中添加了对延迟渲染路径的支持。我们所要做的只是填补G缓冲区。光源在后面的过程中会在后面渲染。那个教程简要地介绍了Unity如何添加这些光源。 这一次,我们将自己渲染这些光源。

为了测试光源,我将使用一个简单的场景,其环境强度设置为零。它用延迟模式下的高动态光照渲染摄像机进行渲染。

测试场景,有方向光源和没有方向光源的效果对比。

场景中的所有对象都使用我们自己的着色器渲染到G缓冲区。但是,这些光源是用Unity的默认延迟着色器渲染的,它被命名为Hidden / Internal-DefferedShader。你可以通过“编辑/项目设置/图形”转到图形设置并将“延迟”着色器模式切换为“自定义着色器”来进行验证。

默认的延迟光源着色器。

使用一个自定义的着色器

每个延迟光源使用单独的渲染通道进行渲染,修改图像的颜色。实际上,它们是图像效果,就像我们之前教程中的延迟渲染下雾的着色器一样。 我们从一个简单的着色器开始,用黑色覆盖一切。

Shader"Custom/DeferredShading"{

Properties {

}

SubShader {

Pass {

Cull Off

ZTest Always

ZWrite Off

CGPROGRAM

#pragma target 3.0

#pragma vertex VertexProgram

#pragma fragment FragmentProgram

#pragma exclude_renderers nomrt

#include "UnityCG.cginc"

structVertexData {

float4 vertex : POSITION;

};

structInterpolators {

float4 pos : SV_POSITION;

};

Interpolators VertexProgram (VertexData v) {

Interpolators i;

i.pos = UnityObjectToClipPos(v.vertex);

returni;

}

float4 FragmentProgram (Interpolators i) : SV_Target {

return0;

}

ENDCG

}

}

}

指示Unity在渲染延迟光源的时候使用此着色器。

使用我们的自定义着色器。

第二个渲染通道

切换到我们的着色器后,Unity抱怨说它没有足够的渲染通道。显然,需要第二个渲染通道。我们只是复制我们已经拥有的渲染通道,看看会发生什么。

Pass {

}

Pass {

}

Unity现在接受我们的着色器并使用它来渲染方向光源。 结果,一切都变黑了。 唯一的例外是天空。模板缓冲区用作掩码以避免在那里渲染,因为方向光源不影响背景。

自定义着色器,照亮和不照亮的效果对比。

但是第二个渲染通道呢? 请记住,当高动态光照渲染被禁用的时候,光源数据被用对数编码。最后一个渲染通道需要、反转这个编码。这是第二个渲染通道的用处。 因此,如果你禁用了摄像机的高动态光照渲染,我们的着色器的第二个渲染通道还是会被使用,一次。

避开对天空的影响

当以低动态光照渲染模式渲染时,你可能会看到天空变黑。 这可能发生在场景视图或游戏视图中。如果天空变黑,那么执行转换的渲染通道没有正确地使用模板缓冲区作为掩码。要解决此问题,请明确设置第二个渲染通道的模板。当我们处理的是非背景部分的片段的时候,我们只应该进行渲染。 通过_StencilNonBackground提供了适当的模板值。

Pass {

Cull Off

ZTest Always

ZWrite Off

Stencil {

Ref [_StencilNonBackground]

ReadMask [_StencilNonBackground]

CompBack Equal

CompFront Equal

}

}

我们可以调试模板缓冲区吗?

不幸的是,帧调试器不会显示有关模板缓冲区的任何信息,也不显示其内容以及通道如何使用。 也许这些信息将在以后的版本中添加。

转换颜色

为了使第二个渲染通道工作,我们必须转换光源缓冲区中的数据。像我们的雾着色器一样,使用UV坐标来绘制全屏的四边形,我们可以使用它来采样缓冲区。

structVertexData {

float4 vertex : POSITION;

float2 uv : TEXCOORD0;

};

structInterpolators {

float4 pos : SV_POSITION;

float2 uv : TEXCOORD0;

};

Interpolators VertexProgram (VertexData v) {

Interpolators i;

i.pos = UnityObjectToClipPos(v.vertex);

i.uv = v.uv;

returni;

}

光源缓冲区本身通过_LightBuffer变量提供给着色器。

sampler2D _LightBuffer;

float4 FragmentProgram (Interpolators i) : SV_Target {

returntex2D(_LightBuffer, i.uv);

}

当没有被照亮的时候,原始的低动态光照渲染数据。

使用公式2-C对低动态光照渲染的颜色进行对数编码。 为了解码,我们必须使用公式-log2 C。

1

return-log2(tex2D(_LightBuffer, i.uv));

当没有被照亮的时候的低动态光照渲染的图像。

现在我们知道它可以正常工作,再次启用高动态光照渲染。

项目文件下载地址:unitypackage

方向光源

第一个渲染通道会负责渲染光源,所以这将是相当复杂的。让我们为它创建一个名为MyDeferredShading.cginc的导入文件。 将渲染通道中的所有代码复制到此文件。

#if !defined(MY_DEFERRED_SHADING)

#define MY_DEFERRED_SHADING

#include "UnityCG.cginc"

#endif

然后在第一个渲染通道导入MyDeferredShading。

Pass {

Cull Off

ZTest Always

ZWrite Off

CGPROGRAM

#pragma vertex VertexProgram

#pragma fragment FragmentProgram

#pragma exclude_renderers nomrt

#include "MyDeferredShading.cginc"

ENDCG

}

因为我们应该添加光照到图像,我们必须确保我们不会移除已经渲染的内容。 我们可以通过更改混合模式来组合完整的源颜色和目标颜色。

1

2

3

4Blend One One

Cull Off

ZTest Always

ZWrite Off

我们需要所有可能的光照配置的着色器变体。multi_compile_lightpasscompiler指令创建我们需要的所有关键字组合。唯一的例外是高动态光照渲染模式。 我们必须为此添加一个单独的多编译指令。

#pragma exclude_renderers nomrt

#pragma multi_compile_lightpass

#pragma multi_compile _ UNITY_HDR_

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农老K

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值