You are asking two different questions in the same post. My answer will address the tricky part of setting a spotlight that accounts for different user-defined parameters.
If you want a light to not illuminate certain GameObjects, simply assign them to a different layer and disable that layer in the Culling Mask property of your Light.
So, you want to design a Spotlight by defining its start and end diameters. However, built-in spotlights in Unity are cone-shaped, with no option for a starting area of light. My solution is a workaround on this, by conveniently setting a spotlight to behave as you want.
Slant angle of a cone
Unity only exposes the Spot Angle variable.
Fortunately, we can solve this with simple trigonometry. Geometrically speaking, a Spotlight resembles a cone. If we look at a cone from the side, its silhouette becomes an isosceles triangle. We can then divide such triangle into two complementary, right triangles:
In this context, \$tan(\theta) = \frac{r}{h}\$ and therefore \$\theta = \arctan(\frac{r}{h})\$. The diameter is twice the radius: \$d = 2r\$. Then, the final formula is:
$$
\theta = \arctan(\frac{d}{2h})
$$.
Slant angle of a truncated cone
Until now, we only had a base diameter. Let's extend this with a new parameter: the top diameter.
The introduction of a new diameter transforms the cone into a truncated cone. A side-view of a truncated cone is an isosceles trapezoid. We can then divide such trapezoid into two complementary, right trapezoid:
We need some more steps before writing a new formula. Let's draw a new line inside one of the right trapezoids, so we divide it into a rectangle and a right triangle:
I'm now assuming you are only interested in the distance between your diameters. So, here \$h\$ represents the truncated cone height, not the whole cone height.
Due to similarity, we know that the whole cone's slant angle and the sub triangle's acute angle are the same value. However, we need the length of the opposite edge. Its value is the difference between the base and top radii: \$l = R-r\$. Let's plug this value into the formula we used before: \$\theta = arctan(\frac{R-r}{h})\$. Finally, let's swap radii for diameters. The final formula is:
$$
\theta = arctan(\frac{D-d}{2h})
$$
Be aware that \$\theta\$ is the Spotlight's cone slant angle, not the Spotlight's Spot Angle. The Spot Angle is simply twice the slant angle.
Sample source code
Let's convert all this maths into code! We are going to create a MonoBehaviour
script. It will compute the values we need when changing its parameters. Once assigned to the Light GameObject, it will update the light properties automatically:
using UnityEngine;
public class CustomSpotlight : MonoBehaviour {
public float SD {
get { return _startDiameter; }
set { _startDiameter = value; }
}
public float ED {
get { return _endDiameter; }
set { _endDiameter = value; }
}
public float H {
get { return _length; }
set {
_length = value;
float theta = Mathf.Atan2(ED-SD, 2*H);
float H_add = SD/(2*Mathf.Tan(theta));
_lt.range = H + H_add;
_lt.spotAngle = 2 * theta * Mathf.Rad2Deg;
_lt.shadowNearPlane = H_add; //EDIT: update near plane distance
transform.localPosition = -H_add * transform.forward;
}
}
[SerializeField]
float _startDiameter = 1f;
[SerializeField]
float _endDiameter = 2f;
[SerializeField]
float _length = 1f;
Light _lt;
void OnValidate() {
_lt = GetComponent<Light>();
_lt.type = LightType.Spot;
SD = _startDiameter;
ED = _endDiameter;
H = _length;
}
}
This code doesn't check against wrong values or trigonometric edge cases, you should include them if you want to use this in production.
After re-computing values, we must also update the light position. We need this offset because e.g. a constant start radius requires the light source position to move back and forth (because the "outside hull" is still a cone).
Then, we must parent the GameObject with the Light
and CustomSpotlight
components to an empty GameObject. Such GO will be used to move and rotate the spotlight around the scene, while its child Light will adjust its local transform to get the desired effect.