实践篇:简单纹理采样

前言:本篇博客只是一个简单的实现普通纹理,光照纹理以及立方体纹理采样功能的例子,主要是当做笔记使用。

核心要点
1.我们可以对1~4维纹理对象进行采样。其中采样接口分别为tex1D,tex2D,tex3D,texCUBE。采样对象类型分别为:sampler,sampler2D,sampler3D,samplerCUBE。采样坐标分别是x,xy,xyz。其中光照纹理采样的最终颜色还要使用DecodeLightmap函数来对tex系列函数获取的颜色进行处理后获取。

2.光照纹理采样对象(unity_Lightmap)和采样系数(unity_LightmapST)都是unity自动传入的。普通纹理的采样系数(纹理对象变量名_ST)也是是unity自动传入的。采样系数变量中的xy代表平铺缩放系数,zw代表平移系数。

3.普通纹理和光照纹理的采样坐标等于纹理原始采样坐标乘以平铺缩放系数再加上偏移系数。立方体纹理的采样坐标等于法线向量与视角向量叉乘获取到的反射向量。

4.普通纹理和光照纹理的采样坐标是不是有效主要看纹理的展开模式的。如果展开模式为Repeat的话,纹理就会在上下左右所有方向平铺,这样采样坐标是一定存在且有效的。如果展开模式为Clamp的话,采样坐标范围就是纹理大小区间,当采样坐标超过纹理大小区间时,采样坐标就是无效的。如图所示:
在这里插入图片描述
而立方体纹理采样坐标是不是有效就是看该采样坐标是否和立方体的面存在相交的像素点,如果存在的话就表明该立方体采样坐标是有效的。

5.采样坐标对应位置的像素是根据纹理过滤模式来获取的。当过滤模式为Point的话,就会获取一个就近的整数像素值。当过滤模式为Bilinear的话,就会获取周围像素按照权重累加的像素值。如图所示:
在这里插入图片描述
光照贴图制作流程
1.构建光照贴图场景:
1>.新建一个cube作为平面,参数设置如图所示:
在这里插入图片描述
2>.新建一个cube和一个sphere,用来接收光照,参数设置如图所示:
在这里插入图片描述在这里插入图片描述
3>.新建一个点光源来照射物体,并将颜色设置为亮色,启动烘焙。参数设置如图所示:
在这里插入图片描述
4>.将原先方向光设置成暖色,启动烘焙。参数设置如图所示:
在这里插入图片描述
5>.跳转摄像机位置,让摄像机看的平面向上一些。参数设置如图所示:
在这里插入图片描述
2.打开光照贴图制作工具(window->lighting),在Scene页签中将环境光也设置成烘焙模式。如图所示:
在这里插入图片描述
然后在Lightmaps页签中选择build来构建光照贴图。参数设置如图所示:
在这里插入图片描述
生成的光照纹理如图所示:
在这里插入图片描述
核心代码:如下所示:

// Upgrade NOTE: replaced tex2D unity_Lightmap with UNITY_SAMPLE_TEX2D

// Upgrade NOTE: commented out 'float4 unity_LightmapST', a built-in variable
// Upgrade NOTE: commented out 'sampler2D unity_Lightmap', a built-in variable

Shader "Custom/sample" {
	Properties {
		// 2d纹理,内部包含纹理贴图以及采样平铺和偏移系数 
		_MainTex ("Albedo (RGB)", 2D) = "white" {}
	}

	SubShader {
		pass {
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "unitycg.cginc"

			struct v2f {
				// 模型世界空间坐标
				float4 pos:POSITION0;
				// 2d纹理采样坐标
				float2 uv_2d:TEXCOORD0;
				// 光照纹理采样坐标
				float2 uv_lm:TEXCOORD1;
			};

			// 2d纹理对象
			sampler2D _MainTex;
			// 2d纹理对象的采样系数,unity自动传入,其中xy分量代表平铺系数,zw、分量代表偏移系数
			float4 _MainTex_ST;
			// 2d光照纹理对象
			sampler2D unity_Lightmap;
			// 2d光照纹理对象采样系数,unity自动传入,其中xy分量代表平铺系数,zw、分量代表偏移系数
			float4 unity_LightmapST;

			v2f vert(appdata_full v)
			{
				v2f o;
				// 将模型空间顶点坐标转换到世界空间中
				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
				// 获取2d纹理对象采样坐标:模型采样坐标乘以平铺系数再加上偏移系数
				o.uv_2d = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
				// 获取2d光照纹理对象采样坐标:模型采样坐标乘以平铺系数再加上偏移系数
				o.uv_lm = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;

				return o;
			}

			fixed4 frag(v2f v):COLOR0
			{
				// 对2d纹理对象进行采样:采样坐标对应像素不存在就获取未知像素,否则如果纹理采用Point模式就会取采样坐标
				// 位置对应的整数像素,如果纹理采用Bilinear模式就会取采样坐标附近像素按照权重累加的像素值
				fixed4 col_2d = tex2D(_MainTex, v.uv_2d);
				// 对2d光照纹理进行采样
				fixed3 col_lm = DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap, v.uv_lm));
				// 返回采样混合色
				return fixed4(col_2d.rgb * col_lm, col_2d.a);
			}
		
			ENDCG
		}
	}
}

运行效果:将上面的shader代码对应材质拖到场景上具有光照纹理的对象上。效果如下图所示:
在这里插入图片描述
立方体纹理采样流程
核心要点:
1.可以将一张纹理在unity设置面板中选择立方体纹理类型,此时就会将该纹理作为立方体纹理的6个面中的一个面。如图所示:
在这里插入图片描述
也可以自己创建一个立方体纹理,并主动设置6个面所需的纹理贴图。如下图所示:
在这里插入图片描述
2.如果要获取动态立方体纹理,此时可以在每一帧中使用相机对6个面进行拍摄来获取纹理贴图;也可以使用摄像机自带的渲染到立方体纹理的接口来获取纹理贴图。然后将新获取的纹理贴图替换旧的立方体纹理中的贴图,从而得到动态的立方体纹理。

3.使用视角向量与法线向量的叉乘获取的反射向量做为采样坐标,这时候在不同的视角下对同一顶点观察到的像素值是不一样的。使用光向量与法线向量叉乘获取的反射向量来作为采样坐标,这时候在不同的视角下对同一顶点观察到的像素值是一样的,这样有背常理。

4.texCUBE内部使用反射向量与立方体的6个面进行相交处理,如果能得到一个相交点,就会将该相交点作为采样结果,否则就说明采样坐标非法,会得到一个未知颜色。

核心代码:

// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'

// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'

Shader "Custom/CubeMap" {
	Properties {
		_Cubemap("Cube Map", Cube) = "white"{}
	}

	SubShader {
		pass {
			CGPROGRAM
			#pragma vertex vert 
			#pragma fragment frag 
			#include "unitycg.cginc"

			struct v2f {
				float4 pos:POSITION0;
				float3 R:POSITION1;
			};

			samplerCUBE _Cubemap;

			v2f vert(appdata_base v)
			{
				v2f o;
				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
				// 获取世界空间中的归一化法线向量:模型到世界的逆矩阵的转置矩阵对法线向量进行变换
				// 由于法线纹理时3阶向量,此时可以将法线向量增加一阶或者去变换矩阵的三阶来处理
				float3 N = normalize(mul(float4(v.normal, 0), unity_WorldToObject)).xyz;
				// 获取世界空间中的视向量:顶点坐标减去摄像机向量=》摄像机指向顶点方向
				float3 V = - WorldSpaceViewDir(v.vertex);
				// 获取当前顶点的反射向量:由于光源方向固定,与法线向量求的反射向量也是固定,从而在
				// 不同角度上获取的顶点颜色是一样的,这是错误的。视角向量角度不同,与法线向量求反射
				// 向量也不同,从而使同一顶点在不同视角下获取的颜色值不一样,这是正确的。
				o.R = reflect(V, N);

				return o;
			}

			fixed4 frag(v2f IN):COLOR0
			{
				// 使用反射向量对立方体纹理进行采样,从而反射纹理与立方体相交面的像素
				fixed4 col = texCUBE(_Cubemap, IN.R);

				return col;
			}
		
			ENDCG
		}
	}
}

运行结果:随便找一张纹理作为立方体纹理,或者创建一个立方体纹理并设置6个面的纹理贴图。
在这里插入图片描述

发布了81 篇原创文章 · 获赞 39 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/zjz520yy/article/details/88915606