11
$\begingroup$

I want to make a building where each window has a randomized lighting value. I can achieve this by separating each window into a separate object and assigning them a material that uses a random number, but is it possible to achieve this without having to separate each window into a separate object?

Ultimately I want to make a city of these skyscrapers, so I imagine it would be computationally way more expensive to have to separate each window into its own object (not to mention annoying having so many objects in the outline editor).

$\endgroup$
3
  • $\begingroup$ I've once asked myself the same question, I didn't find the answer, so what I've finally done is put all the windows into the same object and use select > random, assigned "light on" material, then inversed selection and then assigned "light off" material. Problem: as it's not randomized, if you duplicate your building, it has the same windows disposition that the others... So I'm interested by another trick ;) $\endgroup$
    – moonboots
    Commented Jun 18, 2018 at 20:44
  • $\begingroup$ If your windows are fairly regularly spaced it should be possible to use the texture coordinates and some maths nodes to create a ‘stepped’ value and use that to assingn random state. $\endgroup$ Commented Jun 18, 2018 at 21:53
  • $\begingroup$ I think this addon will work for you. Addon : blendermarket.com/products/window-generator Video : youtube.com/watch?time_continue=1&v=tZu5vRA9x7s $\endgroup$
    – atek
    Commented Jun 19, 2018 at 3:27

2 Answers 2

10
$\begingroup$

Assuming your windows are fairly regularly spaced you can separate the individual 'windows' in the window material by using a Modulo function to convert each of the X,Y,Z Object coordinates into a 'stepped' function. This separates the surface into individual 'cells'. By carefully setting the spacing of the 'cells' (the Modulo functions) to match the positions of the windows you can ensure each 'window' has a consistent solid illumination.

The 'stepped' coordinates are then randomized via a Noise texture and Greater Than used to illuminate only those above a threshold (higher threshold results in fewer 'lit' windows).

Further combine the Object Info 'Random' property into the coordinates (multiplied by a suitable amount so as to make the different objects wildly different) and you have random 'cells' per "building".

This produces the following material :

material

With the following result (this is showing the 'lights' only - obviously the surrounding building needs to also be included in your final mesh) :

result Note : Don't forget to Apply Scale so that the lighting 'cells' are the same dimensions over each object.

For less regularly spaced 'windows' you will need to adjust the Maths nodes to produce the required arrangement of 'window cells'.


There is another way, borrowing a technique used in Per face vertex coloring - essentially to create a UV map where each face is represented by only one pixel in the image. This UV map can then be used as coordinates in the noise texture used to determine whether each 'window' is illuminated.

There are two ways of achieving this :

  1. Using a script

Paste the following script into a Text Editor window :

# Run this script to generate a UV map and Image with 1 pixel per face so each face has a single colour.

import bpy
import bmesh
import math

# Get selected/active object
obj = bpy.context.object
obj.update_from_editmode()
bpy.ops.object.mode_set(mode='EDIT')
bm = bmesh.from_edit_mesh(obj.data)

# Get count of faces
num_faces = len(bm.faces)

# Create UV map
obj.data.uv_textures.new("facepixels_"+str(num_faces))
uv_layer = bm.loops.layers.uv[0]
bm.faces.layers.tex.verify()

# Process each face and position each loop vertex around the centre point
faceidx = -1
for f in bm.faces:
    faceidx = faceidx + 1
    loopidx = -1
    numverts = len(f.loops)
    for l in f.loops:
        loopidx = loopidx + 1
        luv = l[uv_layer]
        luv.uv[0] = float(faceidx)
        luv.uv[1] = 0.5

Select your 'windows' object (with one face per window) and click 'Run Script'. This will generate a new UV map with 1 pixel per face.

  1. Manually

Unwrap the 'windows' mesh using 'Lightmap pack'.

enter image description here

Then in the UV Editor select all the faces, ensure 'Individual Origins' transformation mode is set and scale to zero (Select all (A) then scale to zero with S0Enter). This should produce the following result :

enter image description here

Note how each face has become a single point in the UV.

You can now use the UV Map (whether created manually or via the above unwrapping method) in the following material :

material2

The Add and Multiply adjust the 'Random' object info value to adjust the noise for each separate mesh (building) - you can adjust those to get different random patterns. Adjust the Greater Than node to affect the threshold for which windows are illuminated for more/fewer lights.

$\endgroup$
3
  • $\begingroup$ Thank you very much! I had spent ages trying to accomplish this and couldn't find the answer anywhere. That being said, this only works if the windows are predictably spaced. I'm still wondering if it'd be possible to obtain a separate random number seed for each individual face within an object. $\endgroup$ Commented Jun 19, 2018 at 1:47
  • $\begingroup$ No worries - glad to help. Actually, there is another way - where you could use a UV map with one face per window, with each face shrunken down to a single pixel so the whole face gets a uniform color. See blender.stackexchange.com/a/80299/29586. I’ll try and expand on this a bit when I get the chance. $\endgroup$ Commented Jun 19, 2018 at 5:07
  • $\begingroup$ @JeremyBernier I've updated the answer with a method that uses UV unwrapped faces to allow for any arrangement of windows. $\endgroup$ Commented Jun 19, 2018 at 8:26
5
$\begingroup$

You can go much farther than merely making randomly colored squares on the outside of the building -- with OSL, you can make those squares have the appearance of interior rooms (with parallax), and this basic technique is used all the time in movie VFX.

Code and description of a shader that implements this kind of technique can be found here (the link is for 3DSMax, but it's just an OSL shader that I'm sure can also be used for Blender/Cycles):

http://julius-ihle.de/?p=2451

https://github.com/ADN-DevTech/3dsMax-OSL-Shaders/tree/master/OSL/ADN-User%20Submitted/JuliusIhle

enter image description here

$\endgroup$
1
  • 2
    $\begingroup$ That’s very nice - although using OSL will mean it’s not GPU compatible. I reckon similar could be achieved with nodes - similar to blender.stackexchange.com/a/84618/29586 ... $\endgroup$ Commented Jun 22, 2018 at 10:52

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .