Snow

A simple snow surface implementation is to calculate dot product of normal and a custom direction.

half snowSurfaceMask = clamp(dot(normalWS, _SnowDirection), 0.0f, 1.0f);

It is similar to NdotL. We can add some small scale gradient noise or simple noise to this mask, and make it white. When we change the _SnowDirection, we might add some unwanted artifacts. To solve this problem, multiplying another upward snow mask to the snow surface mask.

Unity Shader

saturate vs. lerp

saturate is compiled to:

// original shader
return saturate(_ColorA);

// compiled
SV_Target0 = _ColorA;
#ifdef UNITY_ADRENO_ES3
    SV_Target0 = min(max(SV_Target0, 0.0), 1.0);
#else
    SV_Target0 = clamp(SV_Target0, 0.0, 1.0);
#endif
return;

lerp is compiled to:

// original shader
return lerp(_ColorA, _ColorB, _ColorLerp);

// compiled
u_xlat16_0 = (-_ColorA) + _ColorB;
SV_Target0 = vec4(_ColorLerp) * u_xlat16_0 + _ColorA;
return;

The malioc’s profiling result is:

saturate:

Main shader
===========

Work registers: 18
Uniform registers: 4
Stack spilling: false
16-bit arithmetic: N/A

                              FMA     CVT     SFU      LS       V       T    Bound
Total instruction cycles:    0.00    0.08    0.00    0.00    0.00    0.00      CVT
Shortest path cycles:        0.00    0.05    0.00    0.00    0.00    0.00      CVT
Longest path cycles:         0.00    0.08    0.00    0.00    0.00    0.00      CVT

FMA = Arith FMA, CVT = Arith CVT, SFU = Arith SFU,
LS = Load/Store, V = Varying, T = Texture

lerp:

Main shader
===========

Work registers: 18
Uniform registers: 4
Stack spilling: false
16-bit arithmetic: N/A

                              FMA     CVT     SFU      LS       V       T    Bound
Total instruction cycles:    0.00    0.08    0.00    0.00    0.00    0.00      CVT
Shortest path cycles:        0.00    0.05    0.00    0.00    0.00    0.00      CVT
Longest path cycles:         0.00    0.08    0.00    0.00    0.00    0.00      CVT

FMA = Arith FMA, CVT = Arith CVT, SFU = Arith SFU,
LS = Load/Store, V = Varying, T = Texture

So they have the same cost performance on profiling.

It worth to notice that the malioc can’t profile the SRP Batcher’s CBuffer, we have to remove the CBuffer when we compile the sahder code. It probably has something to do with hlsl vs. glsl in malioc support. related stackoverflow: https://stackoverflow.com/questions/36115095/hlsl-cbuffer-equivalent-in-glsl

glsl vs. hlsl

OpenGL Shading Language (GLSL) is a high-level shading language and based on C. It is for OpenGL. High-level shading langauge (HLSL) is created by Microsoft.

Lit

The option “Source: Metallic Alpha” and “Source: Albedo Alpha” controls the smoothness’ source. It could be the Metallic Map’s alpha channel or Base Map’s alpha channel.

Lit also uses a function to sample the Metallic Map differently based on workflow and smoothness source.

half4 SampleMetallicSpecGloss(float2 uv, half albedoAlpha)
{
    half4 specGloss;

#ifdef _METALLICSPECGLOSSMAP
    specGloss = SAMPLE_METALLICSPECULAR(uv);
    #ifdef _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
        specGloss.a = albedoAlpha * _Smoothness;
    #else
        specGloss.a *= _Smoothness;
    #endif
#else // _METALLICSPECGLOSSMAP
    #if _SPECULAR_SETUP
        specGloss.rgb = _SpecColor.rgb;
    #else
        specGloss.rgb = _Metallic.rrr;
    #endif

    #ifdef _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
        specGloss.a = albedoAlpha * _Smoothness;
    #else
        specGloss.a = _Smoothness;
    #endif
#endif

    return specGloss;
}

If Metallic Map exists, then the shader will sample the map. Otherwise, the shader will either use _Metallic or _SpecColor to set up metallic value or the the specular light. Then it will calculate smoothness based on the source.

Particle System

IJobParticleSystemParallelFor.Execute

https://docs.unity3d.com/2019.3/Documentation/ScriptReference/ParticleSystemJobs.IJobParticleSystemParallelFor.Execute.html

This job interface essentially makes what GetParticles and SetParticles did more efficiently. The key part of this interface is the event and the job structure.

void OnParticleUpdateJobScheduled() // the job event function
{
	// excute job in here
}

struct ParticleJob : IJobParticleSystemParallelFor
{
	public void Execute(ParticleSystemJobData particles, inti)
	{
		// update particles
	}
}

Please notice that the job script must stay next to the particle system component, otherwise Unity will not call the job event function.

Custom Vertex Stream

We can set custom data in particles vertex. In such away, we can add more data other than POSITION, NORMAL, and UV. For example, Center gives the center particle’s center in particle’s assigned space. We can use it to calculate a sphere mask to control the particle’s movement. Or we can add a vector to [Custom1.xyz](<http://Custom1.xyz>) to give a unifrom moving direction to all particles and use a noise texture to offset them to create a wave.

Math

Perpendicular in 2D

half2 v2;
half2 perpendicular_cw = half2(v2.y, -v2.x); // clock wise
hafl2 perpendicular_ccw = half2(-v2.y, v2.x); // counter clock wise