自发光物体能被烘焙之后是否会影响周围的物体

如图所示:
在这里插入图片描述

这个地面是绿色的,在没有烘焙之前,上面的球体和立方体都是黑色的。
地面使用的材质是A,它使用的shader是unity自己的standard着色器。
上面的球体和立方体使用的材质B,它使用的shader是我们自己编写的shader,这个在博客:
https://blog.csdn.net/wodownload2/article/details/90450421
中有具体的内容。就是采样烘焙之后的光照贴图。

烘焙之后:
在这里插入图片描述
球体和上面的立方体都会被地板的绿色所影响。
也就是说对于自发光的物体,经过烘焙之后,它会对周围的物体产生影响,其间接光信息会被记录在光照贴图中。

金属工作流:DiffuseAndSpecularFromMetallic
关于这个话题,参考:https://catlikecoding.com/unity/tutorials/rendering/part-4/

4.3节 金属工作流

我们日常打交道的有两个基本的分类,一个是金属,另外一个非金属。非金属也叫绝缘材质。目前,我们可以通过设置很强的specular tint来创建一个金属。而用一个很弱的单色镜面反射,来创建一个绝缘材质,这个就是镜面反射工作流。

如果我们能在金属和非金属之间切换这样会更简单一些。由于金属没有漫反射,所以我们能够使用颜色数据来代替specular tint。而非金属呢没有镜面反射,所以我们根本不需要specular tint。这个就是金属工作流。

哪个是更好的工作流呢?
两个方法都很好。这就是为啥unity对每个方法都实现了一个标准的shader。金属工作流更加的简单,因为你只有一个滑动条和一个颜色。这个能够很好的创建写实的材质了。镜面工作流也可以产生同样的效果,但是你需要更多的控制,非写实的材质也能被创建出来。

我们可以使用另外一个滑动条,作为金属开关,来代替specular tint。典型的,它应该是0或者1,因为一个东西要么是金属,要么是非金属。在0到1之间,则是金属和非金属的混合。

	Properties {
		_Tint ("Tint", Color) = (1, 1, 1, 1)
		_MainTex ("Albedo", 2D) = "white" {}
//		_SpecularTint ("Specular", Color) = (0.5, 0.5, 0.5)
		_Metallic ("Metallic", Range(0, 1)) = 0
		_Smoothness ("Smoothness", Range(0, 1)) = 0.1
	}//			float4 _SpecularTint;
			float _Metallic;
			float _Smoothness;

这样我们就可以从albedo和metallic属性中得到specular tint了。albedo就简单通过1-metallic 得到。

			float3 specularTint = albedo * _Metallic;
				float oneMinusReflectivity = 1 - _Metallic;
//				albedo = EnergyConservationBetweenDiffuseAndSpecular(
//					albedo, _SpecularTint.rgb, oneMinusReflectivity
//				);
				albedo *= oneMinusReflectivity;
				
				float3 diffuse =
					albedo * lightColor * DotClamped(lightDir, i.normal);

				float3 halfVector = normalize(lightDir + viewDir);
				float3 specular = specularTint * lightColor * pow(
					DotClamped(halfVector, i.normal),
					_Smoothness * 100
				);

但是,这个过于简化。因为即使是纯的绝缘体也会有一点的镜面反射。所以镜面反射强度和反射值和金属滑动条的值不匹配。这个和颜色空间有关系,幸运的是,UnityStandardUtils有一个方法DiffuseAndSpecularFromMetallic ,为我们考虑到这个问题了。

float3 specularTint; // = albedo * _Metallic;
float oneMinusReflectivity; // = 1 - _Metallic;
//				albedo *= oneMinusReflectivity;
albedo = DiffuseAndSpecularFromMetallic(
	albedo, _Metallic, specularTint, oneMinusReflectivity
);

一个细节就是金属滑动条支持gamma空间。但是简单的值是不会被unity进行gamma矫正的,当使用线性空间的时候。我们可以使用Gamma属性来告诉unity,我们需要对metallic滑动条进行gamma矫正。

[Gamma] _Metallic ("Metallic", Range(0, 1)) = 0

不幸的是,镜面反射对于非金属材质表现还是比较模糊的,所以我们需要一个更好的计算光照的方法,这个就是基于物理的渲染PBS。

如果上面的屋顶是透明的情况,烘焙有没有影响呢。

透明物体怎么写shader
下面我么要写一个透明的物体的shader。

透明物体首先要有要给标签,而且这个标签是subshader层级的, 不能放在pass中。

在这里插入图片描述

我们提供一个枚举来来选择物体是否是透明物体。

 public enum ObjectType
 {
     Opaque,
     Transparent,
 }

下面是shader代码:

Shader "My/My First Lighing Shader"
{
	Properties
	{
		_Color("Tint",Color)= (1,1,1,1)
		_MainTex("MainTex",2D) = "white"{}
		[HideInInspector] _SrcBlend("_SrcBlend", Float) = 1
		[HideInInspector] _DstBlend("_DstBlend", Float) = 0
		[HideInInspector] _zWrite("_ZWrite", Float) = 1
	}

	SubShader
	{
		Pass
		{
			Blend[_SrcBlend][_DstBlend]
			ZWrite[_ZWrite]

			CGPROGRAM
			#pragma vertex MyVertexProgram
			#pragma fragment MyFragmentProgram
			#pragma multi_compile _ _Transparent
			#include "UnityCG.cginc"
			#include "My Lighting.cginc"
			ENDCG
		}
	}

	CustomEditor "ShaderUI"
}

需要一个变体_Tranparent,所以使用#pragma multi_compile _ _Transparent

然后需要在不透明的时候,设置一个渲染模式。在透明的时候,需要另外要给渲染模式。

 public struct RenederSettings
  {
      public RenderQueue queue;
      public BlendMode srcBlend, dstBlend;
      public bool zWrite;

      public static RenederSettings[] settings =
      {
          new RenederSettings()
          {
              queue = RenderQueue.Geometry, //不透明物体
              srcBlend = BlendMode.One, //混合方式 1 0
              dstBlend = BlendMode.Zero,
              zWrite = true //不透明物体是开启深度测试,并且写入
          },
          new RenederSettings()
          {
              queue = RenderQueue.Transparent, //透明物体
              srcBlend = BlendMode.SrcAlpha, //源alpha
              dstBlend = BlendMode.OneMinusSrcAlpha, //1-srcAlpha
              zWrite = false    //关闭深度写入,防止发生闪烁
          }
      };
  }

#if !defined(MY_LIGHTINGdddd)
#define MY_LIGHTINGdddd
#include "Lighting.cginc"


float4 _Color;
uniform sampler2D _MainTex;
uniform float4 _MainTex_ST;


struct VertexData
{
	float4 vertex:POSITION;
	float2 uv:TEXCOORD0;
	float2 uv1:TEXCOORD1;	
};

struct Interpolators  
{
	float4 pos:SV_POSITION;
	float2 uv:TEXCOORD0;
	float2 lightmapUV:TEXCOORD1;
};

struct FragmentOutput
{
	float4 color:SV_Target;	
};

Interpolators MyVertexProgram(VertexData v)
{
	Interpolators i;
	i.pos = UnityObjectToClipPos(v.vertex);
	i.uv = TRANSFORM_TEX(v.uv, _MainTex);
	i.lightmapUV = v.uv1 * unity_LightmapST.xy + unity_LightmapST.zw;
	return i;
}

FragmentOutput MyFragmentProgram(Interpolators i)
{
	FragmentOutput output;
	#if defined(_Transparent) 
		output.color = tex2D(_MainTex, i.uv)*_Color.a;
	#else
		output.color = float4(DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap, i.lightmapUV)),1);
	#endif
	return output;
}

#endif

如果是透明物体,则采样主纹理和乘以_Color.a;
如果是不透明物体,则直接采样光照贴图。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值