【图形学】30 前向渲染多光照场景代码理解
来源:《UNITY SHADER入门精要》
文章目录
- 1、代码理解
1、代码理解
我们现在要注意光源的 5 个属性:位置、方向、颜色、强度、衰减。
在理解代码之前,我们依然需要熟悉我们的理论,主要我们要设置两个 Pass,注意它们的不同的特性,和要做的事情。
注意,据书中所说,注意两个 Pass 中的 #pragma multi_complie_fwdbase
命令和 #pragma multi_complie_fwdadd
命令,在官方文档中没有说明,但是,实验表明,只有使用了这两个编译指令,我们才可以在相关的 Pass 访问到光照变量、、光照衰减值等等的变量。
Shader "Unity Shaders Book/Chapter 9/Forward Rendering" {Properties {_Diffuse ("Diffuse", Color) = (1, 1, 1, 1)_Specular ("Specular", Color) = (1, 1, 1, 1)_Gloss ("Gloss", Range(8.0, 256)) = 20}SubShader {Tags { "RenderType"="Opaque" }Pass {// Pass for ambient light & first pixel light (directional light)Tags { "LightMode"="ForwardBase" }CGPROGRAM// Apparently need to add this declaration #pragma multi_compile_fwdbase
第 17 句,我们使用了 #pragma 编译命令。#pragma multicomplie_fwdbase
确保我们在 Shader 中使用光照衰减等光照变量可以被正确赋值。这个 Pass 我们称之为 BasePass,正如我们之前概念里提到的那样。
#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"fixed4 _Diffuse;fixed4 _Specular;float _Gloss;struct a2v {float4 vertex : POSITION;float3 normal : NORMAL;};struct v2f {float4 pos : SV_POSITION;float3 worldNormal : TEXCOORD0;float3 worldPos : TEXCOORD1;};v2f vert(a2v v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.worldNormal = UnityObjectToWorldNormal(v.normal);o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;return o;}fixed4 frag(v2f i) : SV_Target {fixed3 worldNormal = normalize(i.worldNormal);fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0, dot(worldNormal, worldLightDir));fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);fixed3 halfDir = normalize(worldLightDir + viewDir);fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss);fixed atten = 1.0;return fixed4(ambient + (diffuse + specular) * atten, 1.0);}ENDCG}
所有的工作都在片元着色器中完成,顶点着色器只是在做了最简单的坐标转换而已。我们这里依然使用了 _LightColor0
来获取光源的强度和 _WorldSpaceLightPos0
来获取场景中的位置。平行光的强度不会衰减,所以,我们这里 atten
赋值为1。
如果一个场景中包含了多个平行光,Unity 会选择最亮的平行光传递给 Base Pass 进行逐像素处理,其他的平行光会按照逐顶点活在 Additional Pass 中按照住像素的方式处理。
Pass {// Pass for other pixel lightsTags { "LightMode"="ForwardAdd" }Blend One OneCGPROGRAM// Apparently need to add this declaration#pragma multi_compile_fwdadd
我们第二个 Pass ,按照理论知识,第 3 行,我们定义为 Addtional Pass,为此,我们首先需要设置 Pass 的渲染路径标签:"LightMode" = "ForwardAdd"
。
第 5 行,我们使用 Blend One One
命令来对结果进行混合,而亲测,选择更容易理解的 Blend SrcAlpha DstAlpha
也能得到正确的效果。
第10 行,我们还要给给出宏指令 #prgma multi_complie_fwdadd
指令,这样才能保证我们在 Addtional Pass 中获得正确的光照变量。
#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"#include "AutoLight.cginc"fixed4 _Diffuse;fixed4 _Specular;float _Gloss;struct a2v {float4 vertex : POSITION;float3 normal : NORMAL;};struct v2f {float4 pos : SV_POSITION;float3 worldNormal : TEXCOORD0;float3 worldPos : TEXCOORD1;};v2f vert(a2v v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.worldNormal = UnityObjectToWorldNormal(v.normal);o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;return o;}
同样,顶点着色器做的事情几乎就是常规的操作。
fixed4 frag(v2f i) : SV_Target {fixed3 worldNormal = normalize(i.worldNormal);#ifdef USING_DIRECTIONAL_LIGHTfixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);#elsefixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos.xyz);#endiffixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0, dot(worldNormal, worldLightDir));fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);fixed3 halfDir = normalize(worldLightDir + viewDir);fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss);#ifdef USING_DIRECTIONAL_LIGHTfixed atten = 1.0;#else#if defined (POINT)float3 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1)).xyz;fixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;#elif defined (SPOT)float4 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1));fixed atten = (lightCoord.z > 0) * tex2D(_LightTexture0, lightCoord.xy / lightCoord.w + 0.5).w * tex2D(_LightTextureB0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;#elsefixed atten = 1.0;#endif#endifreturn fixed4((diffuse + specular) * atten, 1.0);
} ENDCG}}FallBack "Specular"
}
代码中共分为两个部分,第一个部分,第 3-13 行,我们进行第一个部分的处理:
首先,我们仍然使用 _LightColor0
来得到光源的颜色和强度。我们使用 宏定义 #ifdef USING_DIRECTIONAL_LIGHT
来确定当前是否是平行光。因为,如果 Pass 处理的光源是萍乡光,那么 Unity 底层就会定义 USING_DIRECTIONAL_LIGHT
。如果是平行光,那么可以直接使用 _WorldSpaceLightPos0.xyz
得到光源方向。如果是点光源或者聚光灯的话,那么 _WorldSpaceLightPos0.xyz
表示的是世界空间下光源的位置。
第二个部分,第 15-27 行,我们处理不同光源的衰减,如果是平行光的话,那 atten = 1
那就不衰减。如果是点光源或聚光灯,处理更加复杂,本来会涉及大量的开根号、除法等运算,但是为了节省效率,Unity 选择了使用一张纹理作为查找表(Lookup Table, LUT),对这个表取样,以获得光源的衰减值。
例子中的场景有 5 个光源,其中 1 个是平行光,其他 4 个都是点光源。平行光会按照 Base Pass 逐像素的方式处理,其他四个点光源都会按照 Addtional Pass 中逐像素的方式处理,每一个光源都会调用一次 Additional Pass。
但是如果我们手动把场景中的所有光源设置为 Not Important 那么,因为没有在 Bass Pass 中计算逐顶点 和 SH光源,因此场景中的 4 个点光源实际上不会对物体造成任何影响。
【图形学】30 前向渲染多光照场景代码理解相关推荐
- 前向渲染和延迟渲染基本概念
前向渲染和延迟渲染基本概念 前言 这一篇是对之前欠的东西,延迟渲染这个东西具体有很多很多值得钻研的东西,这里只是对概念做一个简单的笔记.如果后续再需要深入了解的话,会再另作笔记. 前向渲染 前向渲染是 ...
- 游戏渲染技术:前向渲染 vs 延迟渲染 vs Forward+渲染(二)
GTA5 2 前向渲染 前向渲染是三个光照技术中最简单的,也是游戏图形渲染中最常见的技术.出于这个原因,也是光照计算最昂贵的技术,它不允许在场景中出现大量的动态光源. 大部分使用前向渲染的图形引擎会采 ...
- 图片渲染延迟_前向渲染与延迟渲染
如果您开发过3D游戏,那么您可能会在现代图形引擎的研究中遇到术语"前向渲染"和"延迟渲染". 而且,通常,您必须选择一种在游戏中使用.但是它们是什么,它们有什么 ...
- 为什么Unreal 4引擎能轻易实时渲染出vray要花半天才能渲染出的场景
为什么Unreal 4引擎能轻易实时渲染出vray要花半天才能渲染出的场景? 这不是真的!This is Unreal! 看了这个文章,大为感慨.如果有人以unreal 4为基础开发渲染软件,和rhi ...
- Nicholas谈UE4高级渲染:动态光照迭代快
GameLook报道/6月5日,2015年第三期GameLook开放日‧虚幻引擎专场活动在上海正式举行,此次活动由Epic Games与GameLook联合主办. 如何用好UE4引擎,发挥其强大的画面 ...
- UnityShader15:前向渲染
一.延迟着色和前向渲染 很可惜的是没有什么前置,OpenGL 本是要写一篇延迟着色的笔记的,但是怎么看这都不属于OpenGL基础的范畴 先考虑最简单的情况:只有最多一个光源,这个时候当然就按照正常渲染 ...
- 【技术美术图形部分】关于前向渲染和延迟渲染
学习参考 [技术美术百人计划]图形 3.4 延迟渲染管线介绍 <Unity Shader 入门精要> 1 Unity的渲染路径 关于渲染路径,我在图形渲染管线1.0中就提过了,但只是初步的 ...
- mouseenter 延迟_前向渲染与延迟渲染
如果您开发过3D游戏,那么您可能会在现代图形引擎的研究中遇到术语"前向渲染"和"延迟渲染". 而且,通常,您必须选择一种在游戏中使用.但是它们是什么,它们有什么 ...
- 前向渲染路径细节 Forward Rendering Path Details
正向渲染路径细节 Forward Rendering Path Details Forward Rendering path renders each object in one or more pa ...
最新文章
- python 源码解析
- mysql zf,mysql workbench建表时PK,NN,UQ,BIN,UN,ZF,AI的含义
- SQL查询交集、并集、差集
- 事务的控制(保存点)
- Windbg+VirtualBox调用内核
- 桃李不言,下自成蹊——《大数据》编辑部祝各位老师节日快乐!
- 我的Android进阶之旅------gt;Android中编解码学习笔记
- PS网页设计教程V——如何在Photoshop中创建一个商业网站布局
- c#windfrom打包_WinForm程序打包教程
- smartsvn.license
- 在线 excel 产品技术调研
- 未来20年内,无人驾驶将颠覆这33大行业
- 漏洞分析---SSLv3降级加密协议Padding Oracle攻击(POODLE)技术分析
- 用户使用报告_分享短视频最新2020年抖音用户画像报告
- 计算机图形图像知识梳理,计算机图形学知识点总结
- [初学Spring Boot](1):打不开localhost:8080/hello
- 1014 福尔摩斯的约会(python)
- 2.	编写一个程序,判断用户输入的是正数还是负数
- mac重启后,桌面壁纸失效的问题
- python基础编程:jenkins配置python脚本定时任务过程图解
热门文章
- 基于轻量级卷积网络的小目标检测--轻量级骨干网络部分
- Flask项目(新闻网站)—— 新闻详情页(点击量累加,用户代码封装)
- JdbcType之作用
- 《中国新歌声》第二季再掀暑期音乐热浪 爱奇艺7月14日全网独播
- Hive基础09、HQL查询语句
- python 打包成exe 1053_Python Windows服务pyinstaller可执行文件错误1053
- rational故障_Rational Performance Tester和Citrix故障排除和最佳实践
- python selenium解决textarea赋值空行问题
- 数学正余弦应用——创建六边形环或者六边形面盘
- 基于Amazon Rekognition构建人脸识别系统