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));
}