Skip to content

Instantly share code, notes, and snippets.

@zensharp
Last active February 7, 2023 17:40
Show Gist options
  • Save zensharp/285868208ef5e75593d7fc797f33741a to your computer and use it in GitHub Desktop.
Save zensharp/285868208ef5e75593d7fc797f33741a to your computer and use it in GitHub Desktop.
Shader Snippets

CG Syntax

Declare constant

static const float PI = 3.14;

Declare constant expression

#define INV_FADE_DISTANCE 1.0 / (_FarFade - _NearFade)

Math

Inverse Linear Interpolation

float alerp(float a, float b, float value) {
	return (value - a) / (b - a);
}

Geometry

Project onto vector (vector projection)

float3 project(float3 a, float3 b) {
	return dot(a, b) / dot(b, b) * b;
}

Project onto plane (vector rejection)

float3 reject(float3 a, float3 b) {
	return a - dot(a, b) / dot(b, b) * b;
}

Compute binormal vector

float3 binormal = cross(float3 normal, float3 tangent) * tangent.w;

Color

Apply HDR Exposure (scalar) to Color

fixed4 color;
#ifndef UNITY_COLORSPACE_GAMMA
color.rgb = LinearToGammaSpace(color.rgb);
#endif
color.rgb = ldexp(color, float intensity);
#ifndef UNITY_COLORSPACE_GAMMA
color.rgb = GammaToLinearSpace(color.rgb);
#endif

Compress

Compresses the color to the range [0, 1]. (Useful for visualizing direction vectors)

float4 compress(fixed4 color) {
	return 0.5 + 0.5 * color;
}

Convert Gamma Color to Exact Linear Color

half4 emissive = half4(_EmissionColor.rgb, 0);
emissive.rgb = half4(
	GammaToLinearSpaceExact(emissive.r),
	GammaToLinearSpaceExact(emissive.g),
	GammaToLinearSpaceExact(emissive.b)
);

Extract HSV

float hsv(float3 color)
{
    float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
    float4 P = lerp(float4(color.bg, K.wz), float4(color.gb, K.xy), step(color.b, color.g));
    float4 Q = lerp(float4(P.xyw, color.r), float4(color.r, P.yzx), step(P.x, color.r));
    float D = Q.x - min(Q.w, Q.y);
    float E = 1e-10;
    return float3(abs(Q.z + (Q.w - Q.y)/(6.0 * D + E)), D / (Q.x + E), Q.x);
}

Transformations

Transform Point

Transform object-space position to clip-space position

UnityObjectToClipPos(float4 vertex)

Transform object-space position to world-space position

mul(unity_ObjectToWorld, float4 vertex)

Transform world-space position to clip-space position

UnityWorldToClipPos(float3 pos);

Transform Vector

Transform object-space vector to world-space vector

UnityObjectToWorldNormal(float4 vector)

Transform Direction

Transform object-space direction to world-space direction

UnityObjectToWorldDir(float4 vector)

Camera

Get direction towards camera (object-space)

ObjSpaceViewDir(float4 vertex)

Get direction towards camera (world-space)

WorldSpaceViewDir(float4 vertex)

Per-vertex camera distance

o.vertex = UnityObjectToClipPos(v.vertex);
float depth = o.vertex.z / o.vertex.w;
depth = LinearEyeDepth(depth);

Per-pixel camera fading

// IN VERT TO FRAGMENT STRUCT
float4 projectedPosition : TEXCOORD0;

// IN VERTEX SHADER
o.projectedPosition = ComputeScreenPos(float4 clipPos);
COMPUTE_EYEDEPTH(o.projectedPosition.z);

// IN FRAGMENT SHADER
float cameraInvFadeDistance = 1.0 / (_CameraFarFade - _CameraNearFade);
float cameraFade = saturate((i.projectedPosition.z - _CameraNearFade) * cameraInvFadeDistance);
  • Warning: COMPUTE_EYEDEPTH will (blindly) access the member "vertex" on the local variable named "v". Make sure this variable exists in the scope when calling COMPUTE_EYEDEPTH.
  • By default, Unity's standard shader template names the local variable "i" instead of "v".

Soft blending

#pragma multi_compile SOFTPARTICLES_ON
#define SOFT_PARTICLE_NEAR_FADE _NearFade
#define SOFT_PARTICLE_INV_FADE_DISTANCE 1.0 / (_FadeFade - _NearFade)
UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture);

// IN VERT TO FRAGMENT STRUCT
#if defined(SOFTPARTICLES_ON)
	float4 projectedPosition : TEXCOORD0;
#endif

// IN VERTEX SHADER
#if defined(SOFTPARTICLES_ON)
	o.projectedPosition = ComputeScreenPos(o.vertex);
	COMPUTE_EYEDEPTH(o.projectedPosition.z);
#endif

// IN FRAGMENT SHADER
#if defined(SOFTPARTICLES_ON)
	float sceneZ = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.projectedPosition)));
	float soft = saturate(((sceneZ - SOFT_PARTICLE_NEAR_FADE) - i.projectedPosition.z) * SOFT_PARTICLE_INV_FADE_DISTANCE);
#endif
  • The SOFTPARTICLES_ON keyword is set depending on your Quality Settings.

Screen

Compute screen space coordinates

// IN VERT TO FRAGMENT STRUCT
float4 projectedPosition : TEXCOORD0;

// IN VERTEX SHADER
o.pos = UnityObjectToClipPos(v.vertex.xyz);
o.projectedPosition = ComputeScreenPos(o.pos);

// IN FRAGMENT SHADER
float2 screenUV = i.projectedPosition.xy / i.projectedPosition.w;

Miscellaneous

Apply custom fog color

UNITY_APPLY_FOG_COLOR(i.fogCoord, fixed4 col, fixed4 fogColor);

Compute world-space root position

The following computes the position without matrix multiplication.

float3(unity_ObjectToWorld[0][3], unity_ObjectToWorld[1][3], unity_ObjectToWorld[2][3]);

Triplanar mapping I

float3 blend = normalize(abs(IN.worldNormal));
blend /= dot(blend, float3(1.0, 1.0, 1.0));
half4 col =
	tex2D(_NoiseTex, IN.texcoord.zy) * blend.x +
	yex2D(_NoiseTex, IN.texcoord.xz) * blend.y +
	tex2D(_NoiseTex, IN.texcoord.xy) * blend.z;

Pearls

  • Non-HDR Color properties are in the current color space
  • HDR Color properties are in the Gamma color space
  • Use sincos() if you need sine and cosine
  • Use ldexp() for multiplying by powers of 2
  • When listing KeywordEnum names, the corresponding CGPROGRAM keywords are converted as follows:
    • If a capital letter is preceeded by a lowercase letter, insert an underscore before the capital letter
    • Replace space characters with an underscore
    • Capitalize all letters

Examples

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment