来源:《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 前向渲染多光照场景代码理解相关推荐

  1. 前向渲染和延迟渲染基本概念

    前向渲染和延迟渲染基本概念 前言 这一篇是对之前欠的东西,延迟渲染这个东西具体有很多很多值得钻研的东西,这里只是对概念做一个简单的笔记.如果后续再需要深入了解的话,会再另作笔记. 前向渲染 前向渲染是 ...

  2. 游戏渲染技术:前向渲染 vs 延迟渲染 vs Forward+渲染(二)

    GTA5 2 前向渲染 前向渲染是三个光照技术中最简单的,也是游戏图形渲染中最常见的技术.出于这个原因,也是光照计算最昂贵的技术,它不允许在场景中出现大量的动态光源. 大部分使用前向渲染的图形引擎会采 ...

  3. 图片渲染延迟_前向渲染与延迟渲染

    如果您开发过3D游戏,那么您可能会在现代图形引擎的研究中遇到术语"前向渲染"和"延迟渲染". 而且,通常,您必须选择一种在游戏中使用.但是它们是什么,它们有什么 ...

  4. 为什么Unreal 4引擎能轻易实时渲染出vray要花半天才能渲染出的场景

    为什么Unreal 4引擎能轻易实时渲染出vray要花半天才能渲染出的场景? 这不是真的!This is Unreal! 看了这个文章,大为感慨.如果有人以unreal 4为基础开发渲染软件,和rhi ...

  5. Nicholas谈UE4高级渲染:动态光照迭代快

    GameLook报道/6月5日,2015年第三期GameLook开放日‧虚幻引擎专场活动在上海正式举行,此次活动由Epic Games与GameLook联合主办. 如何用好UE4引擎,发挥其强大的画面 ...

  6. UnityShader15:前向渲染

    一.延迟着色和前向渲染 很可惜的是没有什么前置,OpenGL 本是要写一篇延迟着色的笔记的,但是怎么看这都不属于OpenGL基础的范畴 先考虑最简单的情况:只有最多一个光源,这个时候当然就按照正常渲染 ...

  7. 【技术美术图形部分】关于前向渲染和延迟渲染

    学习参考 [技术美术百人计划]图形 3.4 延迟渲染管线介绍 <Unity Shader 入门精要> 1 Unity的渲染路径 关于渲染路径,我在图形渲染管线1.0中就提过了,但只是初步的 ...

  8. mouseenter 延迟_前向渲染与延迟渲染

    如果您开发过3D游戏,那么您可能会在现代图形引擎的研究中遇到术语"前向渲染"和"延迟渲染". 而且,通常,您必须选择一种在游戏中使用.但是它们是什么,它们有什么 ...

  9. 前向渲染路径细节 Forward Rendering Path Details

    正向渲染路径细节 Forward Rendering Path Details Forward Rendering path renders each object in one or more pa ...

最新文章

  1. python 源码解析
  2. mysql zf,mysql workbench建表时PK,NN,UQ,BIN,UN,ZF,AI的含义
  3. SQL查询交集、并集、差集
  4. 事务的控制(保存点)
  5. Windbg+VirtualBox调用内核
  6. 桃李不言,下自成蹊——《大数据》编辑部祝各位老师节日快乐!
  7. 我的Android进阶之旅------gt;Android中编解码学习笔记
  8. PS网页设计教程V——如何在Photoshop中创建一个商业网站布局
  9. c#windfrom打包_WinForm程序打包教程
  10. smartsvn.license
  11. 在线 excel 产品技术调研
  12. 未来20年内,无人驾驶将颠覆这33大行业
  13. 漏洞分析---SSLv3降级加密协议Padding Oracle攻击(POODLE)技术分析
  14. 用户使用报告_分享短视频最新2020年抖音用户画像报告
  15. 计算机图形图像知识梳理,计算机图形学知识点总结
  16. [初学Spring Boot](1):打不开localhost:8080/hello
  17. 1014 福尔摩斯的约会(python)
  18. 2. 编写一个程序,判断用户输入的是正数还是负数
  19. mac重启后,桌面壁纸失效的问题
  20. python基础编程:jenkins配置python脚本定时任务过程图解

热门文章

  1. 基于轻量级卷积网络的小目标检测--轻量级骨干网络部分
  2. Flask项目(新闻网站)—— 新闻详情页(点击量累加,用户代码封装)
  3. JdbcType之作用
  4. 《中国新歌声》第二季再掀暑期音乐热浪 爱奇艺7月14日全网独播
  5. Hive基础09、HQL查询语句
  6. python 打包成exe 1053_Python Windows服务pyinstaller可执行文件错误1053
  7. rational故障_Rational Performance Tester和Citrix故障排除和最佳实践
  8. python selenium解决textarea赋值空行问题
  9. 数学正余弦应用——创建六边形环或者六边形面盘
  10. 基于Amazon Rekognition构建人脸识别系统