UnityShader学习教程之<顶点膨胀效果 局部变胖实现思路>

方法一:使用顶点颜色实现

建模的时候和模型师沟通一下,让他们把需要膨胀的部分的顶点颜色设置为指定的颜色,然后我们再shader里面获取到之后,在统一处理

注意:我们对于顶点的处理只能写在顶点着色器里面

A.顶点颜色获取

            struct appdata
            {
                float4 vertex : POSITION;
				float3 normal:NORMAL;
            	float4 texcoord : TEXCOORD0;
            	float4 vertColor:COLOR;
            };

vertColor:COLOR 此属性就是我们从建模软件中传入的顶点颜色,在shader的入口构造函数中可以获取此值,然后根据颜色的深度值来膨胀顶点

B.算法

                v.vertex.xyz += v.normal*_Scale*abs(1-v.vertColor.r);
            	if(v.vertColor.x<1)
            	{
            	float z = (1 - v.vertColor.r);
                v.vertex.xyz += v.normal*(pow(z,_Scale)-1);
                }
            	

这段代码主要是获取顶点颜色之后膨胀顶点,从而达到实现固定位置膨胀的效果

思路二:使用顶点坐标加上算法实现

此算法无需顶点颜色,直接通过顶点坐标来实现,更加平滑,但是没有顶点颜色实现的细节

核心算法:

            v2f vert (appdata v)
            {
                v2f o;
                //y的偏移值
            	float y = sin(v.vertex.y-_YHeight);
                //x的偏移值
            	float x = sin(v.vertex.x-_XHeight);
            	float target =  x*y;
            	if(target<0)
            	{
            		target=0;
            	}
                //跟进xy的偏移值实现顶点的缩放
                v.vertex.xyz +=v.normal*target*_Scale;
            	
            	o.pos = UnityObjectToClipPos(v.vertex);
				o.worldNormal = UnityObjectToWorldNormal(v.normal);
				o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
            	o.projPos = ComputeScreenPos (o.pos);
            	o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                #ifdef LIGHTMAP_OFF
				float3 shLight = ShadeSH9(float4(v.normal, 1.0));
				o.vertexLight = shLight;
#ifdef VERTEXLIGHT_ON
				float3 vertexLight = 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, o.worldPos, o.worldNormal
				);
				o.vertexLight += vertexLight;
#endif
#endif
				TRANSFER_SHADOW(o);//仅仅是阴影
                return o;
            }

主要实现的目标是划定区域(xyz坐标)实现区域的顶点的膨胀效果

  

最终实现的膨胀效果以及可调节的参数如下:

 完整shader:

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "MyShader/PigShader"
{
    Properties
	{
		_Color ("Color", Color) = (1,1,1,1)   
		_Diffuse("diffuse",Color) = (1,1,1,1)
		_MainTex ("Albedo (RGB)", 2D) = "white" {} 
		_Specular("specular",Color) = (1,1,1,1)
		_Gloss("gloss",Range(0,2)) = 0.6
		_DepthColor ("DepthColor", Color) = (1,1,1,1)   
		_YHeight("YHeight",float) = 1
		_XHeight("XHeight",float) = 1
		_Scale("Scale",float) = 1
		_Range("Range",Range(-1,1)) = 0
	}
	SubShader
	{
		Tags { "RenderType" = "Opaque" }
		LOD 100

		Pass//ForwardBase
		{
			Tags{"LightMode"="ForwardBase"}
			CGPROGRAM
// Upgrade NOTE: excluded shader from DX11; has structs without semantics (struct appdata members vertColor)
            #pragma exclude_renderers d3d11
			#pragma multi_compile_fwdbase
			#pragma vertex vert
			#pragma fragment frag

			#include "UnityCG.cginc"
			#include "Lighting.cginc"
			#include "AutoLight.cginc"
		
			fixed4 _Diffuse;
			fixed4 _Specular;
			float _Gloss;
			fixed4 _DepthColor;
			fixed4 _Color;
			float _YHeight;
			float _XHeight;
			sampler2D _MainTex;
            float4 _MainTex_ST;
			float _Scale;
			float _Range;

            struct appdata
            {
                float4 vertex : POSITION;
				float3 normal:NORMAL;
            	float4 texcoord : TEXCOORD0;
            	float4 vertColor:COLOR;
            };
			
            struct v2f
            {
                float4 pos : SV_POSITION;
				float3 worldNormal:TEXCOORD0;
				float3 worldPos:TEXCOORD1;
				float3 vertexLight : TEXCOORD2;
            	float4 projPos:TEXCOORD3;
            	float2 uv : TEXCOORD4;
            	float4 Color:COLOR;
				SHADOW_COORDS(5)//仅仅是阴影
            };


            v2f vert (appdata v)
            {
                v2f o;
            	float y = sin(v.vertex.y-_YHeight);
            	float x = sin(v.vertex.x-_XHeight);
            	float target =  x*y;
            	if(target<0)
            	{
            		target=0;
            	}
                v.vertex.xyz +=v.normal*target*_Scale;
            	
            	o.pos = UnityObjectToClipPos(v.vertex);
				o.worldNormal = UnityObjectToWorldNormal(v.normal);
				o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
            	o.projPos = ComputeScreenPos (o.pos);
            	o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                #ifdef LIGHTMAP_OFF
				float3 shLight = ShadeSH9(float4(v.normal, 1.0));
				o.vertexLight = shLight;
#ifdef VERTEXLIGHT_ON
				float3 vertexLight = 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, o.worldPos, o.worldNormal
				);
				o.vertexLight += vertexLight;
#endif
#endif
				TRANSFER_SHADOW(o);//仅仅是阴影
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
				float3 worldNormal = normalize(i.worldNormal);
				float3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
				fixed4 albedo = tex2D(_MainTex, i.uv);	
            	float diff = max(0,dot(worldLightDir,worldNormal));
				//半漫反射系数
				diff = diff * 0.5 + _Gloss;
				//这个函数计算包含了光照衰减以及阴影,因为ForwardBase逐像素光源一般是方向光,衰减为1,atten在这里实际是阴影值
				UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
				float3 diffcolor = diff * albedo.rgb*atten;
				//最终颜色
				float4 color = float4((diffcolor + ambient) * _Color,_DepthColor.a)*atten;
            	fixed4 endcolor = float4((diffcolor + ambient) * _DepthColor,_DepthColor.a)*atten;
            	fixed s = sin(i.worldPos.y/100);
            	fixed3 fincolor = lerp(endcolor.rgb,color.rgb, s); 
				return float4(fincolor,1);
            }
            ENDCG
        }

		Pass//产生阴影的通道(物体透明也产生阴影)
		{
			Tags { "LightMode" = "ShadowCaster" }

			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma target 2.0
			#pragma multi_compile_shadowcaster
			#pragma multi_compile_instancing // allow instanced shadow pass for most of the shaders
			#include "UnityCG.cginc"

			struct v2f {
				V2F_SHADOW_CASTER;
				UNITY_VERTEX_OUTPUT_STEREO
			};

			v2f vert(appdata_base v)
			{
				v2f o;
				UNITY_SETUP_INSTANCE_ID(v);
				UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
				TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
				return o;
			}

			float4 frag(v2f i) : SV_Target
			{
				SHADOW_CASTER_FRAGMENT(i)
			}
			ENDCG
		}
    }
}

猜你喜欢

转载自blog.csdn.net/xiongwen_li/article/details/125647226