UnityHLSLShader 函数笔记

Unity HLSL模板

{
	Properties {
	}
	SubShader {
		Tags { "RenderType"="Transparent" "RenderPipeline"="UniversalPipeline" }
 
		HLSLINCLUDE
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
			
			CBUFFER_START(UnityPerMaterial)
			CBUFFER_END
		ENDHLSL
 
		Pass {
			Tags 
			{ 
				"LightMode"="UniversalForward"
				"Queue" = "Geometry" 
			}
 
			HLSLPROGRAM
			#pragma vertex vert
			#pragma fragment frag
 
			struct Attributes {
				float4 positionOS	: POSITION;
				float3 normalOS		: NORMAL;
				float4 tangentOS	: TANGENT;
				float2 uv			: TEXCOORD0;
			};
 
			struct Varyings {
				float4 positionCS 	: SV_POSITION;
				float2 uv			: TEXCOORD0;
			};
 
			Varyings vert(Attributes input) {
				Varyings output;
 
				VertexPositionInputs positionInputs = GetVertexPositionInputs(input.positionOS.xyz);
				output.positionCS	= positionInputs.positionCS;
				
				output.uv  = input.uv;

				return output;
			}
			
			half4 frag(Varyings input) : SV_Target {

				return 1;
			}
			ENDHLSL
		}
	}
}

粒子模板

Shader "Instance"
{
    Properties {
    }
	SubShader {
		Tags { "RenderType"="Transparent" "RenderPipeline"="UniversalPipeline" }
 
		HLSLINCLUDE
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

			CBUFFER_START(UnityPerMaterial)
			CBUFFER_END
			
			UNITY_INSTANCING_BUFFER_START(Props)
				UNITY_DEFINE_INSTANCED_PROP(half3, _InsColor)
			UNITY_INSTANCING_BUFFER_END(Props)

			#define color UNITY_ACCESS_INSTANCED_PROP(Props, _InsColor)
		ENDHLSL
 
		Pass {
			Name ""
			Tags 
			{ 
				"LightMode"="UniversalForward"
				"Queue" = "Geometry" 
			}
			Cull off
 
			HLSLPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma multi_compile_instancing 
 
			struct Attributes {
				float4 positionOS	: POSITION;
				float3 normalOS		: NORMAL;
				float4 tangentOS	: TANGENT;
				float2 uv0			: TEXCOORD0;
			
				UNITY_VERTEX_INPUT_INSTANCE_ID
			};
 
			struct Varyings {
				float4		positionCS 	: SV_POSITION;
				float2		uv			: TEXCOORD0;
				
				UNITY_VERTEX_INPUT_INSTANCE_ID
				UNITY_VERTEX_OUTPUT_STEREO
			};
			
			Varyings vert(Attributes IN) {
				
				Varyings OUT = (Varyings)0;

				UNITY_SETUP_INSTANCE_ID(IN);
    			UNITY_TRANSFER_INSTANCE_ID(IN, OUT);
    			UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
				
				VertexPositionInputs positionInputs = GetVertexPositionInputs(IN.positionOS.xyz);

				OUT.positionCS	= positionInputs.positionCS;
				OUT.uv  = IN.uv0;

				return OUT;
			}
			
			half4 frag(Varyings IN) : SV_Target {

				UNITY_SETUP_INSTANCE_ID(IN);
				UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(IN);

				half3 finalColor = color;
				return half4(finalColor, 1.0h);
			}
			ENDHLSL
		}
	}
}

懒人模板

	#define POS() float4 positionOS	: POSITION
	#define NOS() float3 normalOS	: NORMAL
	#define TOS() float4 tangentOS	: TANGENT
	#define COL() float4 color      : COLOR
	#define UVO() float2 uv         : TEXCOORD0

	#define PCS()   float4 positionCS : SV_POSITION
	#define UV(x1)  float2 uv		  : TEXCOORDx1
	#define PWS(x2) float3 positionWS : TEXCOORDx2
	#define NWS(x3) float3 normalWS   : TEXCOORDx3
	#define SPS(x4) float4 screenPos  : TEXCOORDx4
	#define TBN(x5) float3x3 tbn	  : TEXCOORDx5

	#define InitDir() 	float3 lightDir     = light.direction;\
                  		float3 normalDir    = normalize(IN.normalWS);\
                  		float3 viewDir      = normalize(_WorldSpaceCameraPos - IN.positionWS);
                  		
	#define InitDot() 	float NoL = dot(normalDir, lightDir);\
                  		float NoV = dot(normalDir, viewDir);\
                  		float NoH = dot(normalDir, halfDir);

快速POW 函数

	#define POW5(x) x * x * x * x * x
	#define POW4(x) x * x * x * x
	#define POW2(x) x * x

法线贴图0值

	#define DefaultNormal float3(0.5f, 0.5f, 1.0f)

黄金旋转矩阵

	#define GoldenRatioRotateMatrix float2x2(-0.69541962, 0.71860389, -0.71860389, -0.69541962)

纹理结构体

	struct TexStruct
	{
		Texture2D tex;
		SamplerState sampler_tex;
	};

	struct CubeTexStruct
	{
		TextureCube tex;
		SamplerState sampler_tex;
	};

	TexStruct InitTex2D(Texture2D tex, SamplerState sampler_tex)
	{
    	TexStruct texStruct;
    	texStruct.tex = tex;
    	texStruct.sampler_tex = sampler_tex;

    	return texStruct;
	}

深度纹理获取世界坐标函数

	float4 GetWorldSpacePosByDepth(float depth, float2 uv, float4x4 IVP)
	{
   		 #if defined(UNITY_REVERSED_Z)
    		depth = 1- depth;
   	 	#endif
				
    	float4 ndc = float4(2.0f * uv - 1.0f, 2.0f * depth - 1.0f, 1.0f);
    	float4 worldPos = mul(IVP, ndc);
    	worldPos.xyz /= worldPos.www;
				
    	return worldPos;
	}

TBN构建函数

	float3x3 GetTBN(float4 tangentOS, float3 normalOS)
	{
		float sign = tangentOS.w;
	
		float3 tangentWS   = TransformObjectToWorldDir(tangentOS);
		float3 normalWS    = TransformObjectToWorldNormal(normalOS);
		float3 binormalWS  = normalize(cross(normalWS, tangentWS)) * sign;

		float3x3 TBN = float3x3(
			tangentWS,
			binormalWS,
			normalWS
		);

		return TBN;

		// You should do :
		// float3 normalDir = normalize(mul(normalData, tbn));
	}

	float3 TBNToNormalWS(float4 tangentOS, float3 normalOS, float3 normalTS)
	{
		float3 tangentWS   = TransformObjectToWorldDir(tangentOS);
		float3 normalWS    = TransformObjectToWorldNormal(normalOS);
		float sgn = tangentOS.w;
				
		float3 binormalWS  = cross(normalWS, tangentWS) * sgn;

		normalWS = TransformTangentToWorld(normalTS, float3x3(tangentWS, binormalWS, normalWS));

		return normalWS;
	}

UV中心缩放函数

	float2 UVCenterScale(float2 uv, float scale)
	{
  	  return (uv - float2(0.5f, 0.5f)) * scale + float2(0.5f, 0.5f);
	}

获取MatCapUV

	float2 GetMatCapUV(float3 normalWS, float3 positionWS)
	{
  	  float3 normalVS   = normalize(TransformWorldToViewDir(normalWS));
    	float3 viewPosVS  = normalize(TransformWorldToView(positionWS));
    	float3 viewCross  = cross(viewPosVS, normalVS);
    
    	normalVS = float3(-viewCross.y, viewCross.x, 0);
    
    	float2 matcapUV = normalVS * 0.45f + 0.5f;

    	return matcapUV;
	}

灰度公式

	real GetGray(real3 color)
	{
  	  return color.r * 0.299f + color.g * 0.587f + color.b * 0.114f;
	}

简单粗暴的使用URP阴影

	#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
	#pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
	#pragma multi_compile _ _SHADOWS_SOFT

	// struct
	float4 shadowCoord	: TEXCOORD0;
	
	// vert
	OUT.shadowCoord = TransformWorldToShadowCoord(OUT.positionWS);

	// frag
	half shadow = light.shadowAttenuation;
	
	// After EndHLSL
	UsePass "Universal Render Pipeline/Lit/DepthOnly"
	UsePass "Universal Render Pipeline/Lit/ShadowCaster"

视差公式

	float2 ParallaxRefraction(float3 viewWS, float height, float parallaxScale)
	{
    	float3 viewL = mul(unity_WorldToObject, viewWS);
    	float2 offset = height * viewL.xy;
    	offset.y = -offset.y;
    
    	return parallaxScale * offset;
	}

物理视差公式

	float2 PhysicallyRefraction(float3 frontNormalWS, float3 refractedWS, float height, float mask)
	{
    	float cosAlpha = dot(frontNormalWS, -refractedWS);
    	float dist = height / cosAlpha;
    	float3 offsetW = dist * refractedWS;
    	float2 offsetL = mul(unity_WorldToObject, offsetW).xy;
    
    	return float2(mask, -mask) * offsetL;
	}

表面曲率(主要用于SSS皮肤)

	float SurfaceCurvature(float3 normalDir, float3 positionWS)
	{
    	return saturate( length( fwidth(normalDir) ) / length( fwidth(positionWS) ) );
    }

SDF脸部

	float3 forwardWS      = normalize(TransformObjectToWorldDir(float3(0,0,1)));
	float3 rightWS        = normalize(TransformObjectToWorldDir(float3(1,0,0)));
	float3 lightDir       = -normalize(float3(light.direction.x, 0, light.direction.z));1
	float3 selfForwardDir =  normalize(float3(forwardWS.x, 0, forwardWS.z));
	float3 selfRightDir   =  normalize(float3(rightWS.x, 0, rightWS.z));

	float FdotL = dot(selfForwardDir, lightDir);
	float RdotL = dot(selfRightDir  , lightDir);
	
	float  lightAttenuation = smoothstep(0.0f, 1.0f, FdotL * 0.5f + 0.5f);
				
	float  alpha = step(0.5f, RdotL * 0.5f + 0.5f); 
	float  uvX 	 = lerp(1.0f - IN.uv.x, IN.uv.x, alpha); 
	float2 uv  	 = float2(uvX, IN.uv.y);
	float  SDF 	 = SAMPLE_TEXTURE2D(_SDF, sampler_SDF, uv);
	
	float face_shadow_mask = step(lightAttenuation, SDF);

广告牌

	// Billboard
	float3 BillBoard(float3 positionOS)
	{
		float3 center = float3(0,0,0);
		float3 viewer = TransformWorldToObject(_WorldSpaceCameraPos.xyz);
		float3 normal = normalize(viewer - center);
		float3 up     = abs(normal.y > 0.999f ? float3(0, 0, 1) : float3(0, 1, 0));
		float3 right  = normalize(cross(up, normal));
		float3 centerOffset = positionOS - center;
		float3 billBoardPos = center + right * centerOffset.x + up * centerOffset.y + normal * centerOffset.z;

		return billBoardPos;
	}

法线膨胀

	real3 BumpScaleNormal(real3 normalData, real bumpScale)
	{
   		normalData.xy *= bumpScale;
    	normalData.z  = sqrt( 1 - saturate(dot(normalData.xy, normalData.xy)) );

    	return normalData;
	}

预积分次表面散射

	float Gaussain(float v, float r)
	{
		return 1.0 / sqrt(2.0 * PI * v) * exp( -(r*r)/(2*v) );
	}

	float3 Scatter(float r)
	{
		return    Gaussain(0.0064 * 1.414, r) * float3(0.233, 0.455, 0.649)
				+ Gaussain(0.0484 * 1.414, r) * float3(0.100, 0.336, 0.344)
				+ Gaussain(0.1870 * 1.414, r) * float3(0.118, 0.198, 0.000)
				+ Gaussain(0.5670 * 1.414, r) * float3(0.113, 0.007, 0.007)
				+ Gaussain(1.9900 * 1.414, r) * float3(0.358, 0.004, 0.000)
				+ Gaussain(7.4100 * 1.414, r) * float3(0.078, 0.000, 0.000)
		;
	}
	float3 integrateDiffuseScattering(float cosTheta, float skinRadius)
	{
		float theta = acos(cosTheta);
			
		float3 totalWeight = 0;
		float3 totalLight  = 0;

		float a = -( PI/2 );

		float inc = 0.05;

		while (a <= ( PI/2 ))
		{
			float samploeAngle = theta + a;
			float diffuse = saturate(cos(samploeAngle));
			
			float sampleDist = abs(2.0 * skinRadius * sin(a * 0.5));
			
			float3 weight = Scatter(sampleDist);
			totalWeight += weight;
			totalLight  += diffuse * weight;

			a += inc;
		}

		return totalLight / totalWeight;
	}

假smoothstep函数

	real smooth(real t1, real t2, real x)
	{
		return saturate((x - t1) / (t2 - t1));
	}

极坐标

	real2 PolarCooradinate(real2 cartesianCoordinates)
	{
		real2 center     = real2(0.5, 0.5);
		real2 coordinate = cartesianCoordinates - center;
			
		real angle = (atan2(coordinate.y, coordinate.x) + PI) / (PI * 2);
		real dist  = distance(cartesianCoordinates, center) * 2;
			
		return real2(angle, dist);
	}

随机数的一种

	float Rand(float2 n)
	{
		const half2 jump = half2(1233.224, 1743.335);
		return sin(dot(n, jump));
	}

色散偏移

	real2 RGBSplitUVOffset(real2 uv, real strength)
	{
    	float2 coords = 2.0 * uv - 1.0;
    	float2 end = uv - coords * dot(coords, coords) * strength;
    	float2 delta = (end - uv) / 3.0;
    
    	return delta;

    	///
    	/// R: uv
    	/// G: delta + uv
    	/// B: delta * 2 + uv
	}

KawaseBlur

	real4 KawaseBlur(TEXTURE2D_PARAM(tex, samplerTex), float2 uv, float2 texelSize, half pixelOffset)
	{
    	half4 o = 0;
    	o += SAMPLE_TEXTURE2D( tex, samplerTex, uv + float2(  pixelOffset +0.5,  pixelOffset +0.5 ) * texelSize ); 
    	o += SAMPLE_TEXTURE2D( tex, samplerTex, uv + float2( -pixelOffset -0.5,  pixelOffset +0.5 ) * texelSize ); 
    	o += SAMPLE_TEXTURE2D( tex, samplerTex, uv + float2( -pixelOffset -0.5, -pixelOffset -0.5 ) * texelSize ); 
    	o += SAMPLE_TEXTURE2D( tex, samplerTex, uv + float2(  pixelOffset +0.5, -pixelOffset -0.5 ) * texelSize );
    
    	return o * 0.25;
	}

散景深度

	real CoCDepth(TEXTURE2D_PARAM(_CameraDepthTexture, sampler_CameraDepthTexture), float2 uv, float focusDist, float maxCoC)
	{
    	float depth = SAMPLE_TEXTURE2D(_CameraDepthTexture, sampler_CameraDepthTexture, uv).x;
    	float linearEyeDepth = LinearEyeDepth(depth, _ZBufferParams);

    	half coc = (1.0 - focusDist / linearEyeDepth) * maxCoC;
    	half nearCoC = clamp(coc, -1.0, 0.0);
    	half farCoC = saturate(coc);

    	return saturate((farCoC + nearCoC + 1.0) * 0.5);
	}

VAT HLSL Helper

//
// Helper functions for SideFx Labs VAT (Vertex Animation Texture)
//

// Rotate a vector with a unit quaternion.
float3 VAT_RotateVector(float3 v, float4 q)
{
    return v + cross(2 * q.xyz, cross(q.xyz, v) + q.w * v);
}

// Calculate a texture sample point for a given vertex.
int3 VAT_GetSamplePoint(Texture2D map, float2 uv, float current, float total)
{
    int t_w, t_h;
    map.GetDimensions(t_w, t_h);

    int frame = clamp(current, 0, total - 1); 
    int stride = t_h / total;

    return int3(uv.x * t_w, uv.y * t_h - frame * stride, 0);
}

// Coordinate system conversion (right hand Z-up -> left hand Y-up)
float3 VAT_ConvertSpace(float3 v)
{
    return v.xzy * float3(-1, 1, 1);
}

// Decode an alpha-packed 3D vector.
float3 VAT_UnpackAlpha(float a)
{
    float a_hi = floor(a * 32);
    float a_lo = a * 32 * 32 - a_hi * 32;

    float2 n2 = float2(a_hi, a_lo) / 31.5 * 4 - 2;
    float n2_n2 = dot(n2, n2);
    float3 n3 = float3(sqrt(1 - n2_n2 / 4) * n2, 1 - n2_n2 / 2);

    return clamp(n3, -1, 1);
}

// Vertex function for cloth VAT
void ClothVAT_float(
    float3 position,
    float2 uv1,
    Texture2D positionMap,
    Texture2D normalMap,
    float2 bounds,
    float totalFrame,
    float currentFrame,
    out float3 outPosition,
    out float3 outNormal
)
{
    int3 tsp = VAT_GetSamplePoint(positionMap, uv1, currentFrame, totalFrame);
    float4 p = positionMap.Load(tsp);

    // Position 
    outPosition = position + VAT_ConvertSpace(lerp(bounds.x, bounds.y, p.xyz));

#ifdef _PACKED_NORMAL_ON
    // Alpha-packed normal
    outNormal = VAT_ConvertSpace(VAT_UnpackAlpha(p.w));
#else
    // Normal vector from normal map
    outNormal = VAT_ConvertSpace(normalMap.Load(tsp).xyz);
#endif
}

// Vertex function for fluid VAT
void FluidVAT_float(
    float2 uv0,
    Texture2D positionMap,
    Texture2D normalMap,
    float2 bounds,
    float totalFrame,
    float currentFrame,
    out float3 outPosition,
    out float3 outNormal
)
{
    int3 tsp = VAT_GetSamplePoint(positionMap, uv0, currentFrame, totalFrame);
    float4 p = positionMap.Load(tsp);

    // Position 
    outPosition = VAT_ConvertSpace(lerp(bounds.x, bounds.y, p.xyz));

#ifdef _PACKED_NORMAL_ON
    // Alpha-packed normal
    outNormal = VAT_ConvertSpace(VAT_UnpackAlpha(p.w));
#else
    // Normal vector from normal map
    outNormal = VAT_ConvertSpace(normalMap.Load(tsp).xyz);
#endif
}

// Vertex function for rigid VAT
void RigidVAT_float(
    float3 position,
    float3 normal,
    float3 color,
    float2 uv1,
    Texture2D positionMap,
    Texture2D rotationMap,
    float4 bounds,
    float totalFrame,
    float currentFrame,
    out float3 outPosition,
    out float3 outNormal
)
{
    int3 tsp = VAT_GetSamplePoint(positionMap, uv1, currentFrame, totalFrame);
    float4 p = positionMap.Load(tsp);
    float4 r = rotationMap.Load(tsp);

    // Position offset
    float3 offs = VAT_ConvertSpace(lerp(bounds.x, bounds.y, p.xyz));

    // Pivot from vertex color
    float3 pivot = VAT_ConvertSpace(lerp(bounds.z, bounds.w, color));

    // Rotation quaternion
    float4 rot = (r * 2 - 1).xzyw * float4(-1, 1, 1, 1);

    // Output
    outPosition = VAT_RotateVector(position - pivot, rot) + pivot + offs;
    outNormal = VAT_RotateVector(normal, rot);
}

螺旋膨胀

	void Peek(inout float3 pos, float3 normal, float2 uv)
	{
		float threshold = abs(cos(UNITY_TWO_PI * (uv.x + uv.y) - _Time.x));
		float area = 1 - abs(uv.y - 0.5f) * 2;

    	pos = pos + normal * threshold * area;
	}

按像素数量描边

	float3 norm = mul((float3x3)UNITY_MATRIX_IT_MV, normalize(v.normal));
    float2 offset = TransformViewToProjection(norm.xy);

    float2 width = (_ScreenParams.zw - 1.0) * _OutlineParam.x;
    float3 vpos = UnityObjectToViewPos(v.vertex);
    width *= smoothstep(_OutlineParam.z, _OutlineParam.y, abs(vpos.z));
    float2 pixel_offset = width * sign(offset);

    o.pos.xy += pixel_offset * o.pos.w; //min(o.pos.w, 4);
    // 来源:https://github.com/xuetaolu/URP_ASE_Tutorial/blob/main/Assets/Scenes/shaderDevelop/%E7%AD%89%E5%83%8F%E7%B4%A0%E6%8F%8F%E8%BE%B9/role_outline_dev.shader

PBR Phong

  (roughness2 + 2) * rcp(8) * pow(NoH, roughness) * (KD + oneMinusReflectivity * (1 - Pow4(LoH)))

预编译指令

#pragma instancing_options procedural: (function) // 在顶点着色器前运行一次配置函数
#pragma instancing_options maxcount: (batchSize) // 使用此参数可指定在一个实例绘制调用中绘制的最大实例数。缺省情况下,该值为500。当使用OpenGL或Metal时,Unity将maxcount除以4,并使用结果作为您可以提交的最大批次数。使这个值尽可能小,以匹配您想要绘制的实例数量。例如,要绘制最多1000个实例,在shader脚本中添加maxcount: 1000。较大的值会增加Shader编译时间,并降低GPU性能。
#pragma instancing_options assumeuniformscaling // 使用这一点来指导Unity假设所有实例都有统一的缩放(所有X、Y和Z轴的缩放都相同)。
#pragma editor_sync_compilation // 在第一次使用着色器之前立即对其进行编译,避免使用虚拟着色器。

GGX

real GGXDistribution(real roughness, real NdotH)
{
	real roughness2 = roughness * roughness;
	real NdotH2 = NdotH * NdotH;

	real denomTerm = NdotH2 * (roughness2 - 1) + 1;
				
	real nom = roughness2;
	real denom = PI * denomTerm * denomTerm;

	return nom * rcp(denom);
}

摄像机朝向

-unity_MatrixV[2].xyz

高斯模糊

private void Blur(RenderTexture src, RenderTexture dest)
    {
        int rtW = src.width;
        int rtH = src.height;
 
        RenderTexture buffer0 = RenderTexture.GetTemporary(rtW, rtH, 0);
        buffer0.filterMode = FilterMode.Bilinear;
 
        Graphics.Blit(src, buffer0);
 
        for (int i = 0; i < iteration; i++) {
            _material.SetFloat("_BlurSize", 1.0f + i * blurSize);
 
            RenderTexture buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);
 
            Graphics.Blit(buffer0, buffer1, _material, 0);
 
            RenderTexture.ReleaseTemporary(buffer0);
            buffer0 = buffer1;
            buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);
 
            Graphics.Blit(buffer0, buffer1, _material, 1);
 
            RenderTexture.ReleaseTemporary(buffer0);
            buffer0 = buffer1;
        }
 
        Graphics.Blit(buffer0, dest);
        RenderTexture.ReleaseTemporary(buffer0);
    }
    
    SubShader {
		CGINCLUDE
		
		#include "UnityCG.cginc"
		
		sampler2D _MainTex;  
		half4 _MainTex_TexelSize;    //用于计算相邻像素的纹理坐标的偏移量
		float _BlurSize;
		  
		struct v2f {
			float4 pos : SV_POSITION;
			half2 uv[5]: TEXCOORD0;
		};
		  
		v2f vertBlurVertical(appdata_img v) {
			v2f o;
			o.pos = UnityObjectToClipPos(v.vertex);
			
			half2 uv = v.texcoord;
			
			o.uv[0] = uv;
			o.uv[1] = uv + float2(0.0, _MainTex_TexelSize.y * 1.0) * _BlurSize;
			o.uv[2] = uv - float2(0.0, _MainTex_TexelSize.y * 1.0) * _BlurSize;
			o.uv[3] = uv + float2(0.0, _MainTex_TexelSize.y * 2.0) * _BlurSize;
			o.uv[4] = uv - float2(0.0, _MainTex_TexelSize.y * 2.0) * _BlurSize;
					 
			return o;
		}
		
		v2f vertBlurHorizontal(appdata_img v) {
			v2f o;
			o.pos = UnityObjectToClipPos(v.vertex);
			
			half2 uv = v.texcoord;
			
			o.uv[0] = uv;
			o.uv[1] = uv + float2(_MainTex_TexelSize.x * 1.0, 0.0) * _BlurSize;
			o.uv[2] = uv - float2(_MainTex_TexelSize.x * 1.0, 0.0) * _BlurSize;
			o.uv[3] = uv + float2(_MainTex_TexelSize.x * 2.0, 0.0) * _BlurSize;
			o.uv[4] = uv - float2(_MainTex_TexelSize.x * 2.0, 0.0) * _BlurSize;
					 
			return o;
		}
		
		float4 fragBlur(v2f i) : SV_Target {
			float weight[3] = {0.4026, 0.2442, 0.0545};
			
			float3 sum = tex2D(_MainTex, i.uv[0]).rgb * weight[0];
			
			for (int it = 1; it < 3; it++) {
				sum += tex2D(_MainTex, i.uv[it*2-1]).rgb * weight[it];
				sum += tex2D(_MainTex, i.uv[it*2]).rgb * weight[it];
			}
			
			return float4(sum, 1.0);
		}
		    
		ENDCG
		
		ZTest Always Cull Off ZWrite Off
		
		Pass {
 
			NAME "GAUSSIAN_BLUR_VERTICAL"
			
			CGPROGRAM
			  
			#pragma vertex vertBlurVertical  
			#pragma fragment fragBlur
			  
			ENDCG  
		}
		
		Pass {  
			NAME "GAUSSIAN_BLUR_HORIZONTAL"
			
			CGPROGRAM  
			
			#pragma vertex vertBlurHorizontal  
			#pragma fragment fragBlur
			
			ENDCG
		}
	} 

矩阵朝向改成某个法线方向

float4x4 GetRotateMatrix(float3 original, float3 final)
{
    float3 va = normalize(final);
    float3 vb = normalize(original);

    float3 vs = cross(vb, va);
    float3 v = normalize(vs);

    float ca = dot(vb, va);
    float scale = 1 - ca;
    float3 vt = float3(v.x * scale, v.y * scale, v.z * scale);
    
    float m00 = vt.x * v.x + ca;
    float m11 = vt.y * v.y + ca;
    float m22 = vt.z * v.z + ca;
    vt.x *= v.y;
    vt.z *= v.x;
    vt.y *= v.z;
    
    float m01 = vt.x - vs.z;
    float m02 = vt.z + vs.y;
    float m10 = vt.x + vs.z;
    float m12 = vt.y - vs.x;
    float m20 = vt.z - vs.y;
    float m21 = vt.y + vs.x;

    return float4x4(m00, m01, m02, 0, m10, m11, m12, 0, m20, m21, m22, 0, 0, 0, 0, 1);
}

沿着某个方向旋转

float4x4 RotateAroundAxis(float3 axis, float angle)
{
    float C = cos(angle);
    float S = sin(angle);
    float t = 1 - C;
    float m00 = t * axis.x * axis.x + C;
    float m01 = t * axis.x * axis.y - S * axis.z;
    float m02 = t * axis.x * axis.z + S * axis.y;
    float m10 = t * axis.x * axis.y + S * axis.z;
    float m11 = t * axis.y * axis.y + C;
    float m12 = t * axis.y * axis.z - S * axis.x;
    float m20 = t * axis.x * axis.z - S * axis.y;
    float m21 = t * axis.y * axis.z + S * axis.x;
    float m22 = t * axis.z * axis.z + C;
    float4x4 finalMatrix = float4x4(m00, m01, m02, 0, m10, m11, m12, 0, m20, m21, m22, 0, 0, 0, 0, 1);

    return finalMatrix;
}

##ToneMapping和逆ToneMapping

half3 Tonemap_ACES(half3 x) {
    // Narkowicz 2015, "ACES Filmic Tone Mapping Curve"
    const float a = 2.51;
    const float b = 0.03;
    const float c = 2.43;
    const float d = 0.59;
    const float e = 0.14;
    return (x * (a * x + b)) / (x * (c * x + d) + e);
}

half3 inv_Tonemap_ACES(half3 x) {
    // Narkowicz 2015, "ACES Filmic Tone Mapping Curve"
    const float a = 2.51;
    const float b = 0.03;
    const float c = 2.43;
    const float d = 0.59;
    const float e = 0.14;
    return (-0.59 * x + 0.03 - sqrt(-1.0127 * x*x + 1.3702 * x + 0.0009)) / (2.0 * (2.43*x - 2.51));
}
  • 11
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值