课时73 Fragment shader - 纹理法线与凹凸贴图 1

  • 课时73 Fragment shader - 纹理法线与凹凸贴图 1

  • 课时74 Fragment shader - 纹理法线与凹凸贴图 2

1.灰度图范围0~1,高度图存放高度值。高度图每个像素可以是1或多个字节,一般用不到,可以从灰度图生成法线纹理(比如,将图标的TextureType改为Normalmap,然后勾选“Create from GrayScale”)。

2.需求:编写shader,从灰度图获取法线信息,而不是用上面提到的方法。

3.代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CreateNormalMap : MonoBehaviour {
	//存放灰度图,格式为Default
	//如果是普通彩色图,可以将(r+g+b)/3得到灰度图,但不是标准做法
	public Texture2D tex0;
	//存放生成的法线图,格式为Default
	//由于要被写入,要求不能压缩,可设置为RGB 24 bit
	//图片内容只是在Unity项目内临时做了修改,关闭项目后效果消失,建议做成工具,导出新贴图
	public Texture2D tex1;
	// Use this for initialization
	void Start () {
		for(int h=1;h<tex0.height-1;h++)//避免处理边缘像素点
		for	(int w=1;w<tex0.width-1;w++)
		{
			float uleft=tex0.GetPixel(w-1,h).r;//灰度图的每个分量值都一样
			float uright=tex0.GetPixel(w+1,h).r;
			float u=uright-uleft;

			float vtop=tex0.GetPixel(w,h-1).r;
			float vbottom=tex0.GetPixel(w,h+1).r;
			float v=vbottom-vtop;

			Vector3 vector_u=new Vector3(1,0,u);//构建x轴方向差分向量,叉积之前不需要规范化
			Vector3 vector_v=new Vector3(0,1,v);//构建y轴方向差分向量

			Vector3 N=Vector3.Cross(vector_u,vector_v).normalized;//每个分量范围-1~1

			float r=N.x*0.5f+0.5f;
			float g=N.y*0.5f+0.5f;
			float b=N.z*0.5f+0.5f;

			tex1.SetPixel(w,h,new Color(r,g,b));
		}
		tex1.Apply(false);
	} 
}

效果:

  • 课时75 Fragment shader - 纹理法线与凹凸贴图 3

1.法线纹理贴图的解压方法UnpackNormal函数:dx5中,法线normal的x=>r=>w;y=>g=>y,z(b)由另外两个分量计算得出。所以法线贴图只用到第二(对应g)和第四(对应r)通道。

2.改进生成法线的代码:

3.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CreateNormalMapNew : MonoBehaviour {
	//存放灰度图,格式为Default
	//如果是普通彩色图,可以将(r+g+b)/3得到灰度图,但不是标准做法
	public Texture2D tex0;
	//存放生成的法线图,格式为Default
	//由于要被写入,要求不能压缩,可设置为RGB 24 bit
	//图片内容只是在Unity项目内临时做了修改,关闭项目后效果消失,建议做成工具,导出新贴图
	public Texture2D tex1;
	// Use this for initialization
	void Start () {
		for(int h=1;h<tex0.height-1;h++)//避免处理边缘像素点
		for	(int w=1;w<tex0.width-1;w++)
		{
			float uleft=tex0.GetPixel(w-1,h).r;//灰度图的每个分量值都一样
			float uright=tex0.GetPixel(w+1,h).r;
			float u=uright-uleft;

			float vtop=tex0.GetPixel(w,h-1).r;
			float vbottom=tex0.GetPixel(w,h+1).r;
			float v=vbottom-vtop;

			Vector3 vector_u=new Vector3(1,0,u);//构建x轴方向差分向量,叉积之前不需要规范化
			Vector3 vector_v=new Vector3(0,1,v);//构建y轴方向差分向量

			Vector3 N=Vector3.Cross(vector_u,vector_v).normalized;//法线信息存储于每个分量范围-1~1

			float r=N.x*0.5f+0.5f;
			float g=N.y*0.5f+0.5f;
			float b=N.z*0.5f+0.5f;

			tex1.SetPixel(w,h,new Color(r,g,b));//法线信息存储于rgb中,对应自建shader
			// tex1.SetPixel(w,h,new Color(0,g,0,r));//法线信息存储于ga中,dx5中只用到yw分量,对应系统自带shader
		}
		tex1.Apply(false);
	} 
}

效果:

4.需求:如果法线贴图将法线信息存储在rgb中,实现自定义shader可以解压法线。

5.代码:

Shader "Custom/Lesson74"
{
	Properties
	{
		_Color("Main Color",Color)=(1,1,1,1)
		_MainTex("MainTex",2D)="white"{}
		_BumpMap("NormalMap",2D)="bump"{}
	}
	SubShader
	{
		Tags { "RenderType"="Opaque" }
		LOD 300

		 
			CGPROGRAM
			#pragma surface surf Lambert
			
			sampler2D _MainTex;
			sampler2D _BumpMap;
			fixed4 _Color;

			struct Input{
				float2 uv_MainTex;
				float2 uv_BumpMap;
			};

			void surf (Input IN,inout SurfaceOutput o)
			{
				fixed4 c=tex2D(_MainTex,IN.uv_MainTex)*_Color;
				o.Albedo=c.rgb;
				o.Alpha=c.a;
				float4 cn=(tex2D(_BumpMap,IN.uv_BumpMap));
				o.Normal=cn.rgb*2-1;//取代UnPackNormal方法
			}
			

			ENDCG
		}
		Fallback "Legacy Shaders/Diffuse"
	}

  • 课时76 Fragment shader - 纹理法线与凹凸贴图 4

1.纹理坐标系(切空间坐标系),由法线N,切线t和垂直于法线,切线的B向量组成。

2.需求:自定义Shader在片段程序内对法线贴图进行采样,并计算光照,在光照类型为点光源时也能显示正常。

3.当LightMode=ForwardBase,且场景只有一个点光源时,因为点光源ForwardBase下只能作为非像素光,所以法线计算显示有问题:

4.需要新建通道,LightMode=ForwardAdd。第一个通道可以渲染平行光和非像素光;第二个通道可以渲染平行光外的像素光;两个通道的混合模式为“blend one one”,否则第一个通道不起作用。

5.代码:

Shader "Custom/Lesson76"
{
	//课时76 Fragment shader - 纹理法线与凹凸贴图 4
	Properties{
			_BumpTex("NormalMap", 2D)="white"{}
		}
	SubShader
	{
		Tags { "RenderType"="Geometry" }
		pass{
			tags{"LightMode"="ForwardBase"}//一个平行光,其余为非像素光

			CGPROGRAM

			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"
			#include "lighting.cginc"

			struct v2f{
				float4 pos:POSITION;
				float2 uv:TEXCOORD0;
				float wpos:TEXCOORD1;//世界空间坐标
				float3 lightDir:TEXCOORD2;//切线空间光向量
			};
			sampler2D _BumpTex;
			v2f vert(appdata_tan v)
			{
				v2f o;
				o.pos=UnityObjectToClipPos(v.vertex);
				o.wpos=mul(unity_ObjectToWorld,v.vertex);
				o.uv=v.texcoord.xy;

				//===================构建切线空间(相当于“TANGENT_SPACE_ROTATION;”)==========================
				// float3 binormal=cross(v.tangent.xyz,v.normal);
				// float3x3 rotation=float3x3(v.tangent.xyz,binormal,v.normal);
				//=============================================
				TANGENT_SPACE_ROTATION;//构建切线空间(通用方式)

				o.lightDir=mul(rotation,_WorldSpaceLightPos0.xyz);//转换光向量至切线空间
				
				return o;
			}
			//法线纹理采样要放在片段函数中
			fixed4 frag(v2f IN):COLOR{ 
				float3 L=normalize(IN.lightDir);
				float3 N=UnpackNormal(tex2D(_BumpTex,IN.uv));//来自纹理贴图的法向量已在切线空间
				N=normalize(N);
				
				float ndotl=saturate(dot(N,L));
				fixed4 col=_LightColor0*ndotl;
				//非像素光
				col.rgb+=Shade4PointLights(unity_4LightPosX0,unity_4LightPosY0,unity_4LightPosZ0,
						unity_LightColor[0].rgb,unity_LightColor[1].rgb,
						unity_LightColor[2].rgb,unity_LightColor[3].rgb,
						unity_4LightAtten0,
						IN.wpos,N );
				return col+UNITY_LIGHTMODEL_AMBIENT;
			}

			ENDCG
		}
		//=================================================
		pass{
			tags{"LightMode"="ForwardAdd"}//不止一个像素光
			blend one one
			CGPROGRAM

			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"
			#include "lighting.cginc"

			struct v2f{
				float4 pos:POSITION;
				float2 uv:TEXCOORD0;
				float wpos:TEXCOORD1;//世界空间坐标
				float3 lightDir:TEXCOORD2;//切线空间光向量
			};
			sampler2D _BumpTex;
			v2f vert(appdata_tan v)
			{
				v2f o;
				o.pos=UnityObjectToClipPos(v.vertex);
				o.wpos=mul(unity_ObjectToWorld,v.vertex);
				o.uv=v.texcoord.xy;

				//===================构建切线空间(相当于“TANGENT_SPACE_ROTATION;”)==========================
				// float3 binormal=cross(v.tangent.xyz,v.normal);
				// float3x3 rotation=float3x3(v.tangent.xyz,binormal,v.normal);
				//=============================================
				TANGENT_SPACE_ROTATION;//构建切线空间(通用方式)

				//_WorldSpaceLightPos0表示像素光,如果为平行光,记录方向信息,如果为点光源,记录位置信息
				o.lightDir=mul(rotation,_WorldSpaceLightPos0.xyz);//转换光向量至切线空间
				
				return o;
			}
			//法线纹理采样要放在片段函数中
			fixed4 frag(v2f IN):COLOR{
				float3 L=normalize(IN.lightDir);

				float3 N=UnpackNormal(tex2D(_BumpTex,IN.uv));//来自纹理贴图的法向量已在切线空间
				N=normalize(N);
				
				float ndotl=saturate(dot(N,L));

				float atten=1;
				if(_WorldSpaceLightPos0.w!=0)//表示点光源,计算衰减.否则表示方向光,没有衰减
				{
					atten=1.0/length(IN.lightDir);	
				}

				fixed4 col=_LightColor0*ndotl*atten;
				
				return col+UNITY_LIGHTMODEL_AMBIENT;
			}

			ENDCG
		}
	}
		Fallback "Diffuse"
}

效果:

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值