【图形学】30 前向渲染多光照场景代码理解

这篇具有很好参考价值的文章主要介绍了【图形学】30 前向渲染多光照场景代码理解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

来源:《UNITY SHADER入门精要》

1、代码理解

  我们现在要注意光源的 5 个属性:位置、方向、颜色、强度、衰减
  在理解代码之前,我们依然需要熟悉我们的理论,主要我们要设置两个 Pass,注意它们的不同的特性,和要做的事情。

【图形学】30 前向渲染多光照场景代码理解

  注意,据书中所说,注意两个 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 lights
			Tags { "LightMode"="ForwardAdd" }
			
			Blend One One
		
			CGPROGRAM
			
			// 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_LIGHT
		fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
	#else
		fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos.xyz);
	#endif
				
	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);
				
	#ifdef USING_DIRECTIONAL_LIGHT
		fixed 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;
		#else
			fixed atten = 1.0;
		#endif
	#endif

	return 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 个点光源实际上不会对物体造成任何影响。文章来源地址https://www.toymoban.com/news/detail-419659.html

到了这里,关于【图形学】30 前向渲染多光照场景代码理解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Unity Shader】Unity前向渲染

    ForwardBase Pass(优先渲染),渲染一个逐像素平行光和所有的顶点/球面调和光,阴影只和平行光有关系,那阴影应该是这个Pass中实现的 ForwardAdd Pass(需要和Base配合使用,否则不生效),渲染剩余全部逐像素灯光 Unity会根据场景中各个光源的设置以及这些光源对物体的影响程

    2024年02月08日
    浏览(58)
  • Unity光照渲染设置

    先看效果图   下面是设置 1、将【Edit - Player -Other Settings】Color Space这个调成Linear模式,有更好的阴影效果  2、光照Lighting的设置【Window-Rendering-Lighting Settings】 标注说明: Baked Global IIIumir 这个是GI 就是是否会有反射光线 Final Gather 这个是最后光照的计算,勾选之后光线根据贴图

    2024年02月15日
    浏览(44)
  • Unity | HDRP高清渲染管线学习笔记:Lightmapping(光照烘焙)与Lightmap(光照贴图)

    目录 相关概念 1.渐进式光照贴图烘焙 1.1 渐进式光照贴图烘焙对模型的要求 1.2 渐进式光照贴图烘焙对硬件的要求 1.3 渐进式光照贴图烘焙支持的Unity渲染管线 1.4 进行渐进式光照贴图烘焙结果 1.5 渐进式光照贴图烘焙的CPU版本和GPU版本 1.6 Lighting窗口Lightmapping Settings参数介绍

    2024年02月11日
    浏览(57)
  • Unity学习笔记---2D光照渲染、美术、动画

    Unity 提供三个渲染管线 :一个内置渲染管线和两个可编程渲染管线 (SRP)。两个 SRP 为通用渲染管线 (URP) 和高清渲染管线 (HDRP)。URP 适用于所有平台,而 HDRP 则 旨在用于针对高端 PC 和主机的游戏。 注意 :如果在 Unity 2021 或更高版本中启动一个新项目,则称为 2D (U

    2024年02月09日
    浏览(43)
  • 【GAMES-104现代游戏引擎】4、引擎渲染基础(渲染基础数据、全局光照、PBR、阴影)

    游戏渲染的挑战 一个场景包含成千上万的GO需要的材质、shader、效果都不尽相同,因此 复杂度极高 当代各种硬件的适配难度高,硬件架构一直在变化 高帧率、高分辨率的要求下,使得绘制算法绘制一帧的时间越来越短, 算法效率要求高 绘制系统可以100%的使用显卡,但CPU只

    2023年04月09日
    浏览(50)
  • 微信小程序获取来源场景值

    https://developers.weixin.qq.com/miniprogram/dev/framework/app-service/scene.html#返回来源信息的场景 https://developers.weixin.qq.com/miniprogram/dev/api/base/app/life-cycle/wx.getLaunchOptionsSync.html 场景值列表 只有1008是来源群聊

    2024年02月02日
    浏览(37)
  • unity 2019 内置渲染管线 光照与Lighting面板 参数详解

    本文仅讨论内置渲染管线,高清渲染管线和通用渲染管线不在讨论范围之内 内置渲染管线就是最普通的工程自带的渲染管线 本文使用的Unity版本为2019.4 ,。如果你的版本不同,参数和参数的功能可能不同。 由于作者并非专业技美,只是一个苦逼的码农,难免有错误,请大佬

    2024年02月17日
    浏览(40)
  • Unity | HDRP高清渲染管线学习笔记:HDRP光照系统(二)

    目录 一、光源类型和模式 1. Light组件 1.1 General(通用设置) 1.1.1 LightLayer(光照层) 1.2 Emission(发光设置) 1.3 Shadows(阴影) 二、Light Layer(光源分层) 三、光照探针  1. Light Probe Group组件 2. 使用光照探针的基本步骤 3. Mesh Renderer组件LightProbes下Blend Probes VS Use Proxy Volume 3

    2024年02月07日
    浏览(45)
  • Unity | HDRP高清渲染管线学习笔记:HDRP光照系统(一)

    目录 一、Light组件 1. Angular Diameter 2. Light Appearance 3. Intensity(光照强度) 4. Indirect Multiplier(间接光倍数) 5. Volumetrics(体积雾) 6. Shadows(阴影) 6.1 Shadow Map(阴影贴图) 6.2 Contact Shadow(接触阴影) 二、Reflection Probe组件(反射探针) 1. Type(反射贴图生成的方式) 三、Lig

    2024年02月14日
    浏览(46)
  • unity加载场景后光照变暗

    关于unity加载场景后光照变暗的问题 最近在做场景的加载功能时,发现加载新的场景后整个场景的光照都变暗,但是如果是直接运行当前场景的话就不会,后来才发现原来是选择的光照是realtime实时光照,在一开始的场景时,它的灯光是已经渲染好了,但重新加载的时候灯光

    2024年02月15日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包