大白话版 UnityShader学习(2)-基础纹理研究(二)

大白话版 UnityShader学习(2)-基础纹理研究(二)

根据冯乐乐大小姐的书来进行学习,总结学习经验,分享心得。

单张纹理

光说不练假把式,代码是码着码着就会了。
(1). 创建一个界面scene,然后把天空盒关了,在window/Lighting/skybox里去掉

(2). 新建个材质球,再新建个shader,把shader放到材质球上,双击shader打开,删掉里面的代码,准备开始
(ps:个人建议shader用Surface Shader新手嘛,不能一开始就太难)

(3). 首先我取个名字,工作中取名字很关键,可以让你迅速找到你想到的代码,所以这边我的习惯是:

Shader"ShaderLab/Lesson01_UV"
{

(4). 那么接下来,我们为了使用到纹理,那必须先给他一个可填入的区域,当然这边冯姐姐为了给这个纹理的外形变得更加好看,在这里增加了Blinn-Phong光照模型。这边“white”{}学习的时候我在想,这是个什么玩意,怎么还有{}这个括号,还有这个white是个啥,这边解释一下white是Unity里内置的纹理的名字,可能还有black,blue对吧,我们这边就一般默认white好了。而这个**{}**东西,你乍一看是不是感觉里面应该要有点啥都东西吧,没有错,这个是为了作为他的初始值而存在的,这里面是空出来的,在底层里,如果你的图片放进去了,那么就会在里面填了一堆数字参数,所以不能忘记。

Properties
{
     _Color("光照颜色",Color) = (1.0,1.0,1.0,1.0)    //ps:我这边是为了方便理解所以在里面写的是中文, 工作中是英文最好
     _MainTex("材质放入点",2D) = "white"{}
     _Specular("反射",Color) = (1.0,1.0,1.0,1.0) 
     _Gloss("光源程度范围",Range(8.0,256)) = 20
}

(5). 好,名字,属性,写完,要写语义块了,这里因为我们要使用光照给予材质一些效果,所以我们在Tags里填写模式,这玩意就相当于在各种游戏里的职业,假设一个游戏里你是农民的职业,那么你不仅可以用通用的技能,还能多个种田技能;你是商人的职业,你没有农民的种田技能,但是你会经商,可以用通用的技能,一样的道理。那么既然我们要使用光照,我们就需要选择这个**“职业”**,光照!

SubShader
{
   Pass
   {
      Tags{ “LightMode” = “ForwardBase” }

(6). 然后我们需要使用HLSL里的代码块,所以我们的内容需要写在CGPROGRAM和ENDCG之间,然后定义出来,片元着色器和表面着色器,便于后面进行使用。

CGPROGRAM
		#pragma vertex vert
		#pragma fragment frag

(7). 接下来,选完**“职业”了,还要选“装备”**,#include里的内容就是各种各样强大的装备内容,可以让你有额外的技能可以使用,我这么说有点不严谨,严谨的说这个是Unity内容的一些变量,这些变量可以让你使用,比如说_LightColor0,那么我们使用的话就得获取,所有主流代码中里获取的方法基本上类似,都是这类操作

#include"Lighting.cginc"

(8). Shader里凡是你在Properties里增加的属性,都需要在里面申明出来,否则只是一个名字没有它的意义

uniform fixed4 _Color ;      //为啥定义颜色?因为Unity里的所有光照,实际上就是相当于按照光照的类型给物体上色而已,所以 Light = Color
uniform sampler2D _MainTex ;  //这个sampler2D,顾名思义便是纹理的类型
uniform float4 _MainTex_ST  //你会发现,我擦,这边咋多了一个ST,对,这个地方不是瞎起的,ST是缩放(Scale)和平移(Transformlation)的缩写,前面的名字你可以按你的想法改,当然要跟上面对应,取名字方法**纹理名_ST**。
uniform fixed4 _Specular ;  //反射光
uniform float _Gloss ;   //滑动条也要写进去,申明一下

(9). 接下来就可以使用,我们刚才定义完的表面着色器和片元着色器了,输入和输出是必不可少的。

	struct VertexInput
			{
				float4 vertex : POSITION;      //必须要有,你用顶点要转换到屏幕呢!
				float3 normal : NORMAL;      //既然有光照,就需要法线来进行计算
				float4 texcoord : TEXCOORD0;     //对,没错,存储纹理的,小伙子聪明~             
			};

			struct VertexOutput
			{
				float4 pos : SV_POSITION; //这边是与vertex进行的对应,必须写!
				float3 worldNormal : TEXCOORD0;   //世界法线
				float3 worldPos : TEXCOORD1;   //世界纹理坐标
				half2 uv:TEXCOORD2;            //增加uv,以便在片元中用该坐标进行纹理采样
			};

(10). 定义顶点着色器啦

VertexOutput vert(VertexInput v)
			{
				VertexOutput o;
				o.pos = UnityObjectToClipPos(v.vertex);          //UnityObjectToClipPos这个是unity新版本后内置宏,以此来代替,mul(UNITY_MATRIX_MVP,v.vertex)
				o.worldNormal = UnityObjectToWorldNormal(v.normal);  //UnityObjectToWorldNormal也是一样,计算模型坐标转到世界坐标的法线
				o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;   //世界纹理坐标,计算模型坐标转到世界坐标的法线
 				//o.uv = v.texcoord.xy * _MainTex_ST.xy+_MainTex_ST.zw;  //这个为啥注掉一个,这个是本身的公式,v.texcoord.xy * _MainTex_ST.xy这个结果得出最终的纹理坐标,后面的就是你可以调整它进行偏移。注掉的原因是,下面这个是Unity的内置宏,当然你要使用它的话,得在前面增加一个#include"UnityCG.cginc"
				o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
				return o; 
			}

(11). 接下来我们需要获得的系统参数都获得差不多了,最后我们要在片元着色器上计算纹素值还有光照:

fixed4 frag(VertexOutput i):SV_Target 
			{
				fixed3 worldNormal = normalize(i.worldNormal);       //所有光照系统都需要建立在标准化的基础进行,不然计算会出错,计算世界法线的坐标
				fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));   //同理计算世界光照方向的标准化参数
				fixed3 albedo = tex2D(_MainTex,i.uv).rgb * _Color.rgb;    //这边的反射率,新的知识点,通过将采样结果和颜色属性相乘来获得
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz *albedo;    //环境光,这个纯知识点,给它增加了反射率的功能
				fixed3 diffuse = _LightColor0.rgb * albedo*max(0,dot(worldNormal,worldLightDir));   //漫反射计算公式
                fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));   //标准化一下+1,= =
				fixed3 halfDir = normalize(worldLightDir+viewDir);//标准化一下+2,= =
				fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0,dot(worldNormal,halfDir)),_Gloss); //以上是为了计算出反射做的铺垫,光照部分我就不强调了,之后会补上
				return fixed4 (ambient+diffuse+specular,1.0);  //加起来就是最终的光照了
			}

(12).设置了一个合适的Fallback,但是对于新手村还没出来的学者而言,我不建议加,因为你一旦发现,哎我去怎么粉了,你会慢慢的回去找错误,这样学的会很快

Fallback“Specular”

好,这些内容就是基础纹理的步骤了,上面的代码不能全盘抄,会报错,所以下面附上完整版,但是我还是建议自己写一遍会比较好

Shader"ShaderLab/Lesson01_UV"
{
	Properties
	{
		_Color("颜色",Color) = (1,1,1,1)
		_MainTex("MainTex",2D)="White"{}
		_Specular("反射",Color) = (1,1,1,1)
		_Gloss("反射范围",Range(5.0,256))=20
	}
	SubShader
	{
		Pass
		{
			Tags{"LightMode"="ForwardBase"}
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include"Lighting.cginc"
			#include"UnityCG.cginc"
			uniform float4 _Color;
			uniform sampler2D _MainTex;
			uniform float4 _MainTex_ST;  //这个地方要强调一下,因为这边是需要_ST的
			uniform float4 _Specular;
			uniform float _Gloss; 

			struct VertexInput
			{
				float4 vertex : POSITION;
				float3 normal : NORMAL;
				float4 texcoord : TEXCOORD0;                  
			};

			struct VertexOutput
			{
				float4 pos : SV_POSITION;
				float3 worldNormal : TEXCOORD0;
				float3 worldPos : TEXCOORD1;
				half2 uv:TEXCOORD2; //增加uv,以便在片元中用该坐标进行纹理采样
			};
			VertexOutput vert(VertexInput v)
			{
				VertexOutput o;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.worldNormal = UnityObjectToWorldNormal(v.normal);
				o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;
 				//o.uv = v.texcoord.xy * _MainTex_ST.xy+_MainTex_ST.zw;
				o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
				return o; 
			}
			fixed4 frag(VertexOutput i):SV_Target
			{
				fixed3 worldNormal = normalize(i.worldNormal);
				fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
				fixed3 albedo = tex2D(_MainTex,i.uv).rgb * _Color.rgb;
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz *albedo;
				fixed3 diffuse = _LightColor0.rgb * albedo*max(0,dot(worldNormal,worldLightDir));
                fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
				fixed3 halfDir = normalize(worldLightDir+viewDir);
				fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0,dot(worldNormal,halfDir)),_Gloss);
				return fixed4 (ambient+diffuse+specular,1.0);
			}


			ENDCG
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值