unity3d shader的软高光的金属效果

软高光的金属效果

学了书里的这一章有很多知识我也很不了解,于是查了一些资料,渐渐的明朗了一些,,一下结合书里的知识和网上的资料与我的理解来说明

主要原理是Cook-Torrance光照模型的算法,是BRDF(双向反射分布函数)的一种,具体算法请看后面

新建一个shader

先浏览一下变量

_MainTint 主色调

_RoughnessTex   粗糙度贴图(控制高光大小)

_Roughness 表面粗糙程度

_SpecularColor  高光颜色

_SpecPower  高光强度

_Fresnel   菲涅尔值(反射系数)

	Properties {
		_MainTint ("Diffuse Tint", Color) = (1,1,1,1)
		_MainTex ("Base (RGB)", 2D) = "white" {}
		_RoughnessTex ("Roughness texture", 2D) = "" {}
		_Roughness ("Roughness", Range(0,1)) = 0.5//表面粗糙度 贴图
		_SpecularColor ("Specular Color", Color) = (1,1,1,1)//高光颜色
		_SpecPower ("Specular Power", Range(0,30)) = 2//高光强度
		_Fresnel ("Fresnel Value", Range(0,1.0)) = 0.05
	}

粗糙度越大反射的光越多,所以高光的范围也就越大,像漫反射就是太粗糙了

Fresnel菲涅尔值:

菲涅尔效果是根据观察者的观察表面来调整反射率来实现的。

比如你从水面,油漆表面或者丝绸的正上方看,反射光泽的柔和效果基本没有,如果侧着或平着看的话,反射光泽的柔和效果就很明显,这就是菲涅尔效果。

我们简单地通过点积操作计算表明法线与视线之间夹角的余弦值,再将这个值加权。

对于较平滑表面,加权系数设置较小之间(油漆效果,丝绸等),对于比较凹凸的表面,加权系数设置为更高(水波,液体等)。

算法方面:

主要在LightingMetallicSoft()函数里实现

		inline fixed4 LightingMetallicSoft(SurfaceOutput s, fixed3 lightDir,half3 viewDir, fixed atten)
		{
			float3 halfVector = normalize(lightDir+ viewDir);//normalize转化成单位向量
			float NdotL = saturate(dot(s.Normal, normalize(lightDir)));//入射光与表面法线向量的点积当作漫反射光照强度因子
			float NdotH_raw = dot(s.Normal, halfVector);//两个单位向量的点积得到两个向量的夹角的cos值
			float NdotH = saturate(/*NdotH_raw*/dot(s.Normal, halfVector));//如果x小于0返回 0;如果x大于1返回1;否则返回x;把x限制在0-1
			float NdotV = saturate(dot(s.Normal, normalize(viewDir)));
			float VdotH = saturate(dot(halfVector, normalize(viewDir)));

			float geoEnum = 2.0 * NdotH;
			float3 G1 = (geoEnum * NdotV) / NdotH;
			float3 G2 = (geoEnum * NdotL) / NdotH;
			float3 G =  min(1.0f, min(G1, G2));//取小的

			float roughness = tex2D(_RoughnessTex, float2(NdotH_raw * 0.5 + 0.5, _Roughness)/*uv*/).r;

			float fresnel = pow(1.0-VdotH, 5.0);//pow()函数:求x的y次方(次幂)
			fresnel *= (1.0 - _Fresnel);
			fresnel += _Fresnel;

			float3 spec = float3(fresnel * G * roughness * roughness) * _SpecPower;

			float4 c;
			c.rgb = (s.Albedo * _LightColor0.rgb * NdotL)+  (spec * _SpecularColor.rgb) * (atten * 2.0f);//_LightColor0场景中平行光的颜色
			c.a = s.Alpha;
			return c;
		}

乍看可能有点眼晕,看我慢慢道来。。。= =

参数:

lightDir  光照方向

viewDir  当前坐标的视角方向

atten  光照的衰减值

dot()求点积

两个单位向量的点积得到两个向量的夹角的cos值

入射光与表面法线向量的点积当作漫反射光照强度因子

NdotL = saturate(dot(s.Normal, normalize(lightDir)));

float NdotH_raw = dot(s.Normal, halfVector);

saturate(x)函数    如果x小于0返回 0;如果x大于1返回1;否则返回x;把x限制在0-1

float NdotH = saturate(dot(s.Normal, halfVector));

float NdotV = saturate(dot(s.Normal, normalize(viewDir)));

float VdotH = saturate(dot(halfVector, normalize(viewDir)));

以上求了各种方向的夹角cos值

查了一下维基

http://en.wikipedia.org/wiki/Specular_highlight#Cook.E2.80.93Torrance_model

翻译一下主要部分

Cook–Torrance光照模型用了一个反射(specular)的形式

//v viewDir 意为World Space View Direction。就是当前坐标的视角方向

//N normal法线方向向量

//L light光线方向向量

//H  半角向量用来计算镜面反射(specular reflection)的中间方向矢量(halfway vector)

//E  摄像机/人眼观察的方向向量

//G  几何衰减系数    描述由于微平面(microfacets)产生的自投影

//F  菲涅尔值(反射系数)

//D   微平面分布函数( Beckmann distribution factor )

本shader得算法与wiki的略有不同,

但G的求法完全相同:

如图为维基中求法:

以下为代码:

		<pre name="code" class="cpp">			float geoEnum = 2.0 * NdotH;
			float3 G1 = (geoEnum * NdotV) / NdotH;
			float3 G2 = (geoEnum * NdotL) / NdotH;
			float3 G =  min(1.0f, min(G1, G2));//取小的

方法是完全相同的。

从粗糙贴图的R通道中读取粗糙值roughness = tex2D(_RoughnessTex, float2(NdotH_raw * 0.5 + 0.5, _Roughness)/*uv*/).r;

求菲涅尔值(反射系数)

pow(x,y)函数:求x的y次方(次幂)

fresnel = pow(1.0-VdotH, 5.0);    fresnel *= (1.0 - _Fresnel);fresnel += _Fresnel;高光占整个物体比率 = 菲涅尔值(反射系数) * 几何衰减系数 * 粗糙值的平方再与外部可控的SpecPower高光强度做积spec = float3(fresnel * G * roughness * roughness)
* _SpecPower;

最终反射颜色_LightColor0是场景中平行光的颜色atten是光照的衰减值 c.rgb = (s.Albedo * _LightColor0.rgb * NdotL)+  (spec * _SpecularColor.rgb) * (atten * 2.0f);

给出了三种不同粗糙程度的贴图如下:

粗糙度由上到下依次减弱

最后实现了一个这样的效果:

最右侧是最粗糙的也是亮的范围最大的,,左面的粗糙度依次减小

用胶囊体看的金属效果不是很明显(柔光较明显),各位可以用不同的模型试试

全代码如下:

Shader "Custom/testShader" {
	Properties {
		_MainTint ("Diffuse Tint", Color) = (1,1,1,1)
		_MainTex ("Base (RGB)", 2D) = "white" {}
		_RoughnessTex ("Roughness texture", 2D) = "" {}
		_Roughness ("Roughness", Range(0,1)) = 0.5//表面粗糙度 贴图
		_SpecularColor ("Specular Color", Color) = (1,1,1,1)//高光颜色
		_SpecPower ("Specular Power", Range(0,30)) = 2//高光强度
		_Fresnel ("Fresnel Value", Range(0,1.0)) = 0.05
	}
	SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 200

			CGPROGRAM
#pragma surface surf MetallicSoft
#pragma target 3.0
			//软金属
			sampler2D _MainTex;
		sampler2D _RoughnessTex;//表面粗糙度 贴图
		float _Roughness;//表面粗糙度 值
		float _Fresnel;
		float _SpecPower;
		float4 _MainTint;
		float4 _SpecularColor;
		//viewDir 意为World Space View Direction。就是当前坐标的视角方向
		//N normal
		//V view
		//L light
		//H  半角向量用来计算镜面反射(specular reflection)的中间方向矢量(halfway vector)
		inline fixed4 LightingMetallicSoft(SurfaceOutput s, fixed3 lightDir,half3 viewDir, fixed atten)
		{
			float3 halfVector = normalize(lightDir+ viewDir);//normalize转化成单位向量
			float NdotL = saturate(dot(s.Normal, normalize(lightDir)));//入射光与表面法线向量的点积当作漫反射光照强度因子
			float NdotH_raw = dot(s.Normal, halfVector);//两个单位向量的点积得到两个向量的夹角的cos值
			float NdotH = saturate(/*NdotH_raw*/dot(s.Normal, halfVector));//如果x小于0返回 0;如果x大于1返回1;否则返回x;把x限制在0-1
			float NdotV = saturate(dot(s.Normal, normalize(viewDir)));
			float VdotH = saturate(dot(halfVector, normalize(viewDir)));

			float geoEnum = 2.0 * NdotH;
			float3 G1 = (geoEnum * NdotV) / NdotH;
			float3 G2 = (geoEnum * NdotL) / NdotH;
			float3 G =  min(1.0f, min(G1, G2));//取小的

			float roughness = tex2D(_RoughnessTex, float2(NdotH_raw * 0.5 + 0.5, _Roughness)/*uv*/).r;

			float fresnel = pow(1.0-VdotH, 5.0);//pow()函数:求x的y次方(次幂)
			fresnel *= (1.0 - _Fresnel);
			fresnel += _Fresnel;

			float3 spec = float3(fresnel * G * roughness * roughness) * _SpecPower;

			float4 c;
			c.rgb = (s.Albedo * _LightColor0.rgb * NdotL)+  (spec * _SpecularColor.rgb) * (atten * 2.0f);//_LightColor0场景中平行光的颜色
			c.a = s.Alpha;
			return c;
		}
		struct Input
		{
			float2 uv_MainTex;
		};

		void surf (Input IN, inout SurfaceOutput o)
		{
			half4 c = tex2D (_MainTex, IN.uv_MainTex) * _MainTint;
			o.Albedo = c.rgb;
			o.Alpha = c.a;
		}
		ENDCG
	}
	FallBack "Diffuse"
}

-------by  wolf96

时间: 2024-10-10 21:53:59

unity3d shader的软高光的金属效果的相关文章

【浅墨Unity3D Shader编程】之七 静谧之秋篇: 表面着色器的写法(二)——自定义光照模式

本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://hpw123.net/plus/view.php?aid=183 作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442 邮箱: [email protected] QQ交流群:330595914 更多文章尽在:http://www.hpw123.net 本文主要讲解了Unity中SurfaceShader的自定义光照模式的写法. 上篇文章中我们已经说到,表面着色器将分为两次讲解,上

【浅墨Unity3D Shader编程】之三 光之城堡篇:子着色器、通道与标签的写法 &amp; 纹理混合

本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/41175585 作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442 邮箱: [email protected] 本文介绍了Unity中子着色器.通道和标签相关的详细概念与写法,以及纹理的设置方法,基本的纹理混合写法,写了5个Shader作为本文Shader讲解的实战内容,最后创建了一个梦幻的光之

【浅墨Unity3D Shader编程】之五 圣诞夜篇: Unity中Shader的三种形态对比&amp;混合操作合辑

本系列文章由@浅墨_毛星云 出品,转载请注明出处.  文章链接:http://hpw123.net/a/C__/kongzhitaichengxu/2014/1222/164.html 作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442 邮箱: [email protected] QQ交流群:330595914 更多文章尽在:http://www.hpw123.net 本文算是固定功能Shader的最后一篇,下一次更新应该就会开始讲解表面Shader,而

【淡墨Unity3D Shader计划】五 圣诞用品: Unity在Shader三种形式的控制&amp;amp;混合操作编译

本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/42060963 作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442 邮箱: [email protected] 文章开头,先给自己诚求个游戏研发实习的好去处. 浅墨今年1月.明年上半年有近半年的空暇时间可供实习. 近5年游戏编程经验,能够胜任全职的游戏开发工作.仅仅拿实习生的工资(性价比非常高有

【浅墨Unity3D Shader编程】之二 雪山飞狐篇:Unity的基本Shader框架写法&amp;颜色、光照与材质

本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/40955607 作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442 邮箱: [email protected] 本篇文章中,我们学习了Unity Shader的基本写法框架,以及学习了Shader中Properties(属性)的详细写法,光照.材质与颜色的具体写法.写了6个Shader作为本文S

【译】Unity3D Shader 新手教程(1/6)

刚开始接触Unity3D Shader编程时,你会发现有关shader的文档相当散,这也造成初学者对Unity3D Shader编程望而却步.该系列教程的第一篇文章(译者注:即本文,后续还有5篇文章)详细介绍了Unity3D中的表面着色器(Surface Shader)的,为学习更复杂的Shader编程打下基础. 动机 如果你是刚刚接触Shader编程的新手,你可能不知道从何开始踏出Shader编程的第一步.本教程将带你一步步完成一个表面着色器(Surface Shader)和片段着色器(Fra

Unity3D ShaderLab 使用BlinnPhong高光类型

Unity3D shaderLab 使用BlinnPhong高光类型 上一篇我们实现了自定义高光类型,这一篇,我们说Blinn高光,它是另一种计算和估算高光更高效的方式,它是通过视线防线和光线方向,所形成的半角向量来完成. 这种方式比我们自己形成反射向量来进行计算更加高效.在UnityCG.cginc文件中内置的BlinnPhong光照模型就是半角矢量完成的. 首先还是创建一个shader,一个材质球,双击shader,打开编辑器. 1:Properties Properties { _Main

Unity3D ShaderLab 创建自定义高光类型

Unity3D ShaderLab 创建自定义高光类型 在上一篇,我们认识了Unity基础的高光实现,本次主要是研究如何对Phong高光类型进行顶点操作,以及在表面着色器中使用Input结构体的新参数进行像素操作. 所以还是新建Shader,再建材质球然后打开编辑器进行shader的编辑. 1.修改Properties Properties { _MainTex ("Base (RGB)", 2D) = "white" {} _MainTint("Diff

【浅墨Unity3D Shader编程】之四 热带雨林篇: 剔除、深度测试、Alpha测试以及基本雾效合辑

本系列文章由@浅墨_毛星云 出品,转载请注明出处.   文章链接:http://hpw123.net/a/C__/kongzhitaichengxu/2014/1222/163.html 作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442 邮箱: [email protected] QQ交流群:330595914 更多文章尽在:http://www.hpw123.net 本文介绍了Unity中Shader书写中会用到的剔除.深度测试.Alpha测试以及基