ShaderNote-素描风格的渲染

效果图

在这里插入图片描述

素描

素描效果是非真实渲染章节实现的一个效果,还是蛮有意思的。

实现方法

主要是根据物体的光照系数,来决定哪些浅,哪些深,哪些白,然后再使用这些素描纹理,进行采样填充。
轮廓线的实现,主要是顶点上的偏移,要注意的是它们是在视图空间下 完成计算的,它只计算背面,因此需要 剔除前面。
主要实现

在顶点作色器中计算光照系数,根据光照结果来决定6张为你的混合权重,并传递给片元作色器,然后在片元作色器根据这些权重来混合6张纹理的采样结果。

定义所需的属性

	Properties
	{
		_Color("Color",Color)=(1,1,1,1)
		_TintFactor("TintFactor",float)=8
		_OutLine("OutLine",Range(0,1))=1
		_OutLineColor("OutLineColor",Color)=(1,1,1,1)
		_Hatch0("Hatch 0",2D)="white" {}
		_Hatch1("Hatch 1",2D)="white" {}
		_Hatch2("Hatch 2",2D)="white" {}
		_Hatch3("Hatch 3",2D)="white" {}
		_Hatch4("Hatch 4",2D)="white" {}
		_Hatch5("Hatch 5",2D)="white" {}
	}

计算轮廓线

pass
		{	
			Cull Front 
			Tags{"RenderType"="Opaque" "Queue"="Geometry"}
			  
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"
			float _OutLine;
			float4 _OutLineColor;
			struct a2v
			{
				float4 vertex:POSITION;
				float3 normal:normal;
			};
			struct v2f
			{
				float4 pos:SV_POSITION;
			};
			v2f vert(a2v v)
			{
				v2f o;
				float3 pos=UnityObjectToViewPos(v.vertex);
				float3 normal=mul((float3x3)UNITY_MATRIX_IT_MV,v.normal);
				normal.z=-0.5; //为了防止内凹
				pos=pos+normalize(normal)*_OutLine;
				o.pos=mul(UNITY_MATRIX_P,float4(pos,1));
				return o;
			}
			float4 frag(v2f v):SV_TARGET
			{
				return fixed4(_OutLineColor.rgb,1);
			}
			
			ENDCG
		}

需要剔除前面,在片元着色器中,只计算描边的颜色。
在顶点作色器中
o.pos=mul(UNITY_MATRIX_P,float4(pos,1)); 使用的是当前投影矩阵,把视图空间下计算好偏移的pos转换到当前投影空间下。

如果不设置法线 z可能会出现 这种情况
在这里插入图片描述
视图空间下,法线*offset 就是向外扩展offet倍,归一化后,只得到了垂直物体表面,向外的方向。

另一个通道 处理物体的前面,剔除背面

	pass
		{
			Cull Back
			Tags{"RenderType"="Opaque" "Queue"="Geometry"}

			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma multi_compile_fwdbase
			#include "UnityCG.cginc"
			#include "Lighting.cginc"
			#include "AutoLight.cginc"
			struct a2v{
				float4 vertex:POSITION;
				float3 normal:NORMAL;
				float4 texcoord:TEXCOORD0;
			};	
			struct v2f
			{
				float4 pos:SV_POSITION;
				float2 uv:TEXCOORD0;
				float3 hatchWeight0:TEXCOORD1;
				float3 hatchWeight1:TEXCOORD2;
				float3 worldPos:TEXCOORD3;
				SHADOW_COORDS(4)
			};
			float4 _Color;
			sampler2D _Hatch0;
			sampler2D _Hatch1;
			sampler2D _Hatch2;
			sampler2D _Hatch3;
			sampler2D _Hatch4;
			sampler2D _Hatch5;
			float _OutLine;
			float _TintFactor;

			v2f vert(a2v v)
			{
				v2f o;
				o.pos=UnityObjectToClipPos(v.vertex);
				o.uv=v.texcoord.xy*_TintFactor;
				o.worldPos=mul(unity_ObjectToWorld,v.vertex).xyz;
				float3 worldNormal=normalize( UnityObjectToWorldNormal(v.normal));
				//float3 wordViewDir=normalize(UnityWorldSpaceViewDir(o.worldPos.xyz));
				float3 worldLightDir=-normalize(UnityWorldSpaceLightDir(o.worldPos));
				//float3 halfDir=normalize(wordViewDir+worldLightDir);

				o.hatchWeight0=float3(0,0,0);
				o.hatchWeight1=float3(0,0,0);
				float diff=dot(worldNormal,worldLightDir);
				diff=clamp(diff,0.005,1);//防止背部全黑

				float hatchFactor=diff*7;
				if(hatchFactor>6)
				{
					 
 				}
				else if(hatchFactor>5)
				{
					o.hatchWeight0.x=hatchFactor-5;
				}else if(hatchFactor>4)
				{
					o.hatchWeight0.x=hatchFactor-4;
					o.hatchWeight0.y=1-o.hatchWeight0.x;
				}
				else if(hatchFactor>3)
				{
					o.hatchWeight0.y=hatchFactor-3;
					o.hatchWeight0.z=1-o.hatchWeight0.y;
				}
				else if(hatchFactor>2)
				{
					o.hatchWeight0.z=hatchFactor-2;
					o.hatchWeight1.x=1-o.hatchWeight0.z;
				}
				else if(hatchFactor>1)
				{
					o.hatchWeight1.x=hatchFactor-1;
					o.hatchWeight1.y=1-o.hatchWeight1.x;

				}
				else
				{
					o.hatchWeight1.y=hatchFactor;
					o.hatchWeight1.z=1-o.hatchWeight1.y;
				}

				TRANSFER_SHADOW(o);
				return  o;
			} 

			fixed4 frag(v2f i):SV_TARGET
			{
				fixed4 hatchTex0=tex2D(_Hatch0,i.uv)*i.hatchWeight0.x;		
				fixed4 hatchTex1=tex2D(_Hatch1,i.uv)*i.hatchWeight0.y;		
				fixed4 hatchTex2=tex2D(_Hatch2,i.uv)*i.hatchWeight0.z;		
				fixed4 hatchTex3=tex2D(_Hatch3,i.uv)*i.hatchWeight1.x;		
				fixed4 hatchTex4=tex2D(_Hatch4,i.uv)*i.hatchWeight1.y;		
				fixed4 hatchTex5=tex2D(_Hatch5,i.uv)*i.hatchWeight1.z;		

				fixed4 whiteColor=fixed4(1,1,1,1)*(1-i.hatchWeight0.x-i.hatchWeight0.y-i.hatchWeight0.z-i.hatchWeight1.x-i.hatchWeight1.y-i.hatchWeight1.z);
				fixed4 hatchColor=hatchTex0+hatchTex1+hatchTex2+hatchTex3+hatchTex4+hatchTex4+whiteColor;

				UNITY_LIGHT_ATTENUATION(atten,i,i.worldPos);

				return fixed4(_Color.rgb*atten*hatchColor.rgb,1);
			}
							o.uv=v.texcoord.xy*_TintFactor;
							这里是计算纹理的密集度

在vert中 计算diffuse= dot(n,l) n为法线方向,l为光照方向,
然后扩大7倍,分别对应6张纹理 和全白区域;
分别计算 x0 ,x0y0,y0z0,z0x1,x1y1,z1;的系数

在frag中

				fixed4 whiteColor=fixed4(1,1,1,1)*(1-i.hatchWeight0.x-i.hatchWeight0.y-i.hatchWeight0.z-i.hatchWeight1.x-i.hatchWeight1.y-i.hatchWeight1.z);

这里白色 计算就是 全白色减去上面所有diffuse不为0的情况,
用1 减去,是因为 diffuse 最高为1,代表全亮,这里计算结束,所有剩下的就是亮的部分了。

				fixed4 hatchColor=hatchTex0+hatchTex1+hatchTex2+hatchTex3+hatchTex4+hatchTex4+whiteColor;

最后最终结果就是它们所有 采样的颜色相加;
0,1,2,3,4,5,分别代表 模型的各个部分。
由浅到深。
最后再计算光照衰减, 就完成了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值