You copied the Doc URL to your clipboard.

Fading out the cone edges

In the plane parallel to the cross section, fade out the light shaft intensity depending on the relative camera-to-vertex orientation.

In the vertex shader, project the camera position on the cross section.

Build a new vector from the center of the cross section to the projection, and normalize it.

Calculate the dot product of this vector with the vertex normal, then raise the result to a power exponent.

Pass the result to the fragment shader as a varying. This is used to modulate the intensity of the light shaft.

The vertex shader performs these calculations in the Local Coordinate System (LCS).

The following code shows the vertex shader:

// Project camera position onto cross section
float3 axisY = float3(0, 1, 0);
float dotWithYAxis = dot(camPosInLCS, axisY);
float3 projOnCrossSection = camPosInLCS - (axisY * dotWithYAxis);
projOnCrossSection = normalize(projOnCrossSection);

// Dot product to fade the geometry at the edge of the cross section 
float dotProd = abs(dot(projOnCrossSection, input.normal));
output.overallIntensity = pow(dotProd, _FadingEdgePower) * _CurrLightShaftIntensity;

The coefficient _FadingEdgePower enables you to fine-tune the fading of the light shaft edges.

The script passes the coefficient _CurrLightShaftIntensity. This makes the light shaft fade out when the camera gets close to it.

The following code shows a final touch that is added to the light shaft by slowly scrolling down the texture from a script:

void Update()
	float localOffset = (Time.time * speed ) + offset;
	localOffset = localOffset % 1.0f;
	GetComponent<Renderer>().material.SetTextureOffset("_MainTex", new Vector2(0, localOffset));

The fragment shader fetches the beam and mask textures, and then combines them with the intensity factor:

float4 frag(vertexOutput input) : COLOR
	float4 textureColor = tex2D(_MainTex, input.tex.xy);
	float textureMask = tex2D(_MaskTex,;
	textureColor *=  input.overallIntensity * textureMask;
	textureColor.rgb = clamp(textureColor.a, 0, 1);
	return textureColor;				

The light shaft geometry is rendered in the transparent queue after all the opaque geometry.

It uses additive blending to combine the fragment color with the corresponding pixel in the frame buffer.

The shader also disables culling and writing to depth buffer so it does not occlude other objects.

The settings for the pass are:

Blend One One
Cull Off
ZWrite Off
Was this page helpful? Yes No