On this page |
Light instancing is a convenient way to illuminate a scene with hundreds or even thousands of individual lights. Points will determine where the lights appears. This method is interesting for streets, buildings, amusement parks, airports, and any other scenarios that requires a large number of lights. It’s also possible to control or randomize properties like intensity or color.
Basic considerations ¶
As always in Houdini, there are several ways to achieve a goal and light instancing is no exception. You can, for example, use the Instancer LOP with a prototype light source and control the properties through VEX. Another, more convenient, way is to set up your scene inside a SOP network and randomize the light sources with a
USD Configure Prims from Points SOP.
The configure node is not only good for authoring attributes/primvars, but you can also determine a prim(itive) type. This means that a point cloud carries information that creates a particular type of primitive in Solaris, for example a light source or a cube. Once you've chosen a prim type, the node provides parameters to adjust the primitive’s attributes. For lights you can directly determine color or intensity.
If you're familiar with scattering in Houdini, then you’ll immediately recognize that this process is basically adding USD-specific attributes to scatter points.
Scatter points ¶
On the Solaris stage, create a SOP Create LOP. Then, look for the node’s Import Path Prefix and change it to your needs to create an entry in the Scene Graph Tree. All light sources will be grouped under this path. In this example, the path is
/World/lights
.
Double-click the node to dive inside. The first step is to lay down a point source. The points determine, where the lights will finally appear. You can use any point source, but they all must have one thing in common for use with the USD Configure Prims from Points SOP: the points must be free-floating. Typical examples for free-floating point sources are:
-
Scatter points from the
Scatter SOP and
Scatter and Align SOP
-
Base geometry with Primitive Type set to Points
-
Points from POP simulations
The images in this guide were created from a Circle (Polygons) SOP’s points. The Circle SOP doesn’t provide a points mode, so it was necessary to remove the polygons manually, for example with a
Primitive Wrangle SOP. The following one-liner deletes the object’s polygons at the wrangle’s first input:
removeprim(0, @primnum, 0);
Lights ¶
Also inside the SOP Create SOP, add a USD Configure Prims from Points SOP and connect its input with the last upstream node. Now, open the Prim Type dropdown menu to see the available primitives. From the list, choose RectLight to create a rectangular area light. When you take a look at the Prim Type Attributes section, you can see the parameters you can modify. Turn on Color and Intensity.
Also make sure that the Path or Name parameter is turned on, because it’s a mandatory requirement for the configure node. If you don’t want to use default paths, complete the Path parameter as well. The prefix should match the SOP Create LOP’s _Path Prefix. In this example scene, the correct path is:
/World/lights/`chs("primtype")`_@elemnum
When you return to the stage level, you can see the lights' gizmos at the locations of the scatter points. If you want to start a preview render, choose a Karma delegate from the viewport’s first dropdown menu (set to Perspective by default). To finally see the lights it’s often necessary to render against a background, for example a grid.
The Scene Graph Tree shows copies of the lights grouped under the configure node’s Path. Right now, the copies have identical colors and intensities. Maybe you're also not happy with the orientation of the lights?
Orientation ¶
To change orientation, dive inside the SOP Create LOP again. One convenient way is to use a Scatter and Align SOP upstream of the configure node. The interesting thing with Scatter and Align is that you can not only adjust orientation, but also scale. Of course, you can also apply VEX scripts or any other method.
-
Connect both inputs of the scatter node with the point source.
-
On the scatter node, open the Mode dropdown menu and choose Add Attributes to Existing Point Clouds.
-
Use the parameters of the Orientation tab to adjust rotation angles and alignment axes.
Randomization ¶
You can now randomize the active attributes of the configure prims node. In this case it was Color and Intensity. In fact, there are countless ways of adding randomness to attributes. One possible way is to use nodes from the Attribute Adjust SOPs family, because they come preconfigured in many flavors. Next to each parameter of the Prim Type Attributes section you can see an icon. When you click it, the configure node creates an appropriate Attribute Adjust SOP, for example an Attribute Adjust Color SOP or an
Attribute Adjust Float SOP for attributes like
intensity
. The buttons are very convenient, because you don’t have to worry about the attribute’s signature.
For the color values, click the button to create and connect a downstream Attribute Adjust Color SOP. On the Adjustment Value, change Pattern Type to Random. Now you can define a Color Ramp or apply one of the
Presets.
For the Intensity value, click the button and you’ll get a new Attribute Adjust Float SOP. On the General section’s Attribute Name parameter, enter
intensity
. Then, go to Adjustment Value and set Pattern Type to Random. You can define random intensities ranging from Min Value to Max Value, for example 2
and 6
. The Remap Ramp gives you more control over the intensities. The Intensity parameter on the configure node acts as a multiplier for the random values.
Of course, you can combine color, intensity, and any other available parameter to get a fully randomized array of lights.
Selective randomization ¶
You can work with the scatter like with any other point source and you can create groups. The USD Configure Prims from Points provides a Groups parameter. With groups its possible to subdivide a point source and treat each part individually. You’ll need an appropriate number of configure prims nodes - one for each group. With the Group SOP’s sophisticated Keep by parameters you’ll be able to define groups based on specific properties like normals or edges. Note that group nodes must be added upstream of the configure prim node.
If you work with multiple groups, for example to create differently colored lights, you must change the Path to split the lights. The reason is that, by default, the light primitives wear an index (@lemenum
). If you don’t split the lights, indices will be overridden and some lights won’t appear in the rendering. Imagine a scene with blue and yellow lights. In such a case, possible path definitions are:
/World/lights/`chs("primtype")`_B_@elemnum /World/lights/`chs("primtype")`_Y_@elemnum
Alternatively, you can also create two branches for the lights as in this example:
/World/lights/blue/`chs("primtype")`_@elemnum /World/lights/yellow/`chs("primtype")`_@elemnum
The image below shows a possible result with a Group by Range SOP where every third light source is yellow.
Instancing ¶
If you're more familiar with Houdini, you’ll recognize that each light source is a true copy, not an instance. Physical copies always need more resources. There’s also a more advanced (and less convenient) method that uses an Instancer LOP, an
Area Light LOP and some VEX. The light source is the so-called prototype. A prototype represents the primitive that will be instanced.
This workflow also requires that you create scatter points in a SOP network, for example directly inside the Instancer SOP. Then you connect the light node to the instancer’s second input to establish a connection between light and points. The instancer also has a Primitive Path that lets you define where in the Scene Graph Tree the instances will appear, for example under /World/lights
. The Scene Graph Tree also shows the difference between the SOP-based and the instancing method: Instead of a long list with light primitives, the tree now only shows a short entry like /World/lights/Prototypes/lights/arealight1
.
In terms of point attributes you have the same possibilities as with the purely SOP-based method and you can author orientation
or pscale
. However, if you want to change the light’s very own properties like color or intensity, you need a different solution, for example a VEX script.
Light-specific primvars ¶
The VEX script will do what the USD Configure Prims from Points LOP did for you in the previous chapters: adding light-specific primvars.
To customize the instances, you need an Attribute Wrangle LOP. Add the node and connect its first input with the output of the instancer. Before you can start to add the VEX code, it’s necessary to prepare the wrangle.
-
Turn on Run on Elements of Array Attributes. This option makes sure that the VEX code is executed for each light instance. As a side effect, you’ll get access to the
elemnum
primvar - a unique identifier for each instance. This number is important to address each instance individually. -
You also have to define the length of the array that contains the attributes: It’s the number of points that also determines the number of lights. From the Array Length dropdown menu, choose Number of Point Instances.
Intensities ¶
The following code alters intensities between a customizable minimum and maximum.
int intensity_seed = @elemnum + chi("intensity_seed"); @primvars:light:intensity = fit(random(intensity_seed), 0, 1, ch("min_intensity"), ch("max_intensity"));
Use ⌃ Ctrl + C to copy the code below and paste it with ⌃ Ctrl + V to the wrangle’s VEXPression input field.
The script takes values from three custom parameters that are encapsulated inside the ch()
commands. To add the parameters to the UI, click the Creates spare parameters for each unique call of ch() button. Based on
elemnum
, the script calculates an individual seed for each instance that drives a random()
function. random()
creates a number between 0 and 1. The fit()
function, on the other hand, remaps the random number to a range between min_intensity
and max_intensity
.
The key instruction is @primvars:light:intensity
. This definition authors the intensity
primvar/attribute to the points. With this notation you can address several other light parameters like:
-
exposure (
exposure
) -
width (
width
) -
(
height
) -
color (
color
) -
color temperature (
colorTemperature
) -
diffuse multiplier (
diffuse
) -
specular multiplier (
specular
)
Colors ¶
If you want to apply random colors, you can copy and paste the following code:
int color_seed = @elemnum + chi("color_seed"); v@primvars:light:color = vector(chramp("color_ramp", random(color_seed)));
The chramp()
function describes a new custom parameter and you can add it with the button. What happens inside the brackets is another remapping process. The code creates a random number for each instanced light. Based on this value, a color is chosen and applied.
It’s important to note that @primvar
is explicitly introduced as a vector by adding a v
prefix. Colors consist of three components and are considered vectors. The chramp()
part is also prefixed with a vector. This little trick will add a color ramp instead of a basic ramp with floats.