Book Image

HLSL Development Cookbook

By : Doron Feinstein
Book Image

HLSL Development Cookbook

By: Doron Feinstein

Overview of this book

3D graphics are becoming increasingly more realistic and sophisticated as the power of modern hardware improves. The High Level Shader Language (HLSL) allows you to harness the power of shaders within DirectX 11, so that you can push the boundaries of 3D rendering like never before.HLSL Development Cookbook will provide you with a series of essential recipes to help you make the most out of different rendering techniques used within games and simulations using the DirectX 11 API.This book is specifically designed to help build your understanding via practical example. This essential Cookbook has coverage ranging from industry-standard lighting techniques to more specialist post-processing implementations such as bloom and tone mapping. Explained in a clear yet concise manner, each recipe is also accompanied by superb examples with full documentation so that you can harness the power of HLSL for your own individual requirements.
Table of Contents (13 chapters)

Spot light


Spot light is a light source that emits light from a given position in a cone shape that is rounded at its base. The following screenshot shows a spot light pointed at the bunny's head:

The cone shape of the spot light is perfect for representing flash lights, vehicle's front lights, and other lights that are focused in a specific direction.

Getting ready

In addition to all the values needed for point light sources, a spot light has a direction and two angles to represent its cone. The two cone angles split the cone into an inner cone, where light intensity is even, and an outer cone, where light attenuates if it gets closer to the cone's border. The following screenshot shows the spot light direction as D, the inner to outer cone angle as α, and the outer cone angle as θ:

Unlike the point light, where light intensity attenuates only over distance, spot lights intensity also attenuates across the angle α. When a light ray angle from the center is inside the range of α, the light gets dimmer; the dimmer the light, the closer the angle is to θ.

How to do it...

For the spot light calculation, we will need all the values used for point light sources plus the additional three values mentioned in the previous section. The following deceleration contains the previous and new values:

cbuffer SpotLightConstants : register( b0 )
{
  float3 SpotLightPos      : packoffset( c0 );
  float SpotLightRangeRcp  : packoffset( c0.w );
  float3 SpotLightDir      : packoffset( c1 );
  float SpotCosOuterCone   : packoffset( c1.w );
  float SpotInnerConeRcp   : packoffset( c2 );
}

Like the directional light's direction, the spot light's direction has to be normalized and inverted, so it would point to the light (just pass it to the shader, minus the light direction). The inverted direction is stored in the shader constant SpotLightDir.

Reciprocal range is stored in the shader constant SpotLightRangeRcp.

When picking the inner and outer cone angles, always make sure that the outer angle is bigger than the outer to inner angle. During the spot light calculation, we will be using the cosine of the inner and outer angles. Calculating the cosine values over and over for every lit pixel in the pixel shader is bad for performance. We avoid this overhead by calculating the cosine values on the CPU and passing them to the GPU. The two angle cosine values are stored in the shader constants SpotCosOuterCone and SpotCosInnerCone.

The code to calculate the spot light is very similar to the point light code:

float3 CalcSpot(float3 position, Material material)
{
   float3 ToLight = SpotLightPos - position;
   float3 ToEye = EyePosition.xyz - position;
   float DistToLight = length(ToLight);
   
   // Phong diffuse
   ToLight /= DistToLight; // Normalize
   float NDotL = saturate(dot(ToLight, material.normal));
   float3 finalColor = SpotColor.rgb * NDotL;
   
   // Blinn specular
   ToEye = normalize(ToEye);
   float3 HalfWay = normalize(ToEye + ToLight);
   float NDotH = saturate(dot(HalfWay, material.normal));
   finalColor += SpotColor.rgb * pow(NDotH, material.specExp) * material.specIntensity;
   
   // Cone attenuation
   float conAtt = saturate((cosAng - SpotCosOuterCone) * SpotCosInnerConeRcp);
   conAtt *= conAtt;
   
   // Attenuation
   float DistToLightNorm = 1.0 - saturate(DistToLight * SpotLightRangeRcp);
   float Attn = DistToLightNorm * DistToLightNorm;
   finalColor *= material.diffuseColor * Attn * conAtt;
   
   return finalColor;
}

As with the previous two light functions, this function takes the pixel's world position and material values, and outputs the pixel's lit color value.

How it works…

As with the previous light sources, the spot light is using the Blinn-Phong model. The only difference in the code is the cone attenuation, which gets combined with the distance attenuation. To account for the cone shape, we first have to find the angle between the pixel to light vector and the light vector. For that calculation we use the dot product and get the cosine of that angle. We then subtract the cosine of the outer cone angle from that value and end up with one of the three optional results:

  • If the result is higher than the cosine of the inner cone, we will get a value of 1 and the light affect will be fully on

  • If the result is lower than the cosine of the inner cone but higher than zero, the pixel is inside the attenuation range and the light will get dimmer based on the size of the angle

  • If the result is lower than zero, the pixel was outside the range of the outer cone and the light will not affect the pixel