VI-Suite v0.4 – Version 0.4.11 & Sky View Factor Calculation

Version 0.4.11 has now been released. This version contains a number of bug fixes and new features,  including the ability to create a sun path with hourly or monthly suns and a new Sky View Factor node. A zip file containing the VI-Suite addon for Blender version 2.7.8 has also been released for Linux 64bit systems. See the changelog page for more details.

The sky view factor (or VI SVF) node operates in a similar manner to the Shadow Map node except that instead of checking if a point can be seen from the perspective of simulated sun positions it is checked if it can be seen from different portions of the sky. The sky can be subdivided into 145 portions (Tregenza) 577 portions (Reinhart 577) or 2305 portions (Reinhart 2305). Accuracy and simulation time increases with each one.

The VI Sky View Factor node can be added through the ‘Analysis Nodes’ menu. An image of the node is shown below. Options are similar as for the Shadow Map node except there is no location input required and no time options, as sky view factor is location and time independent. The ‘Results Out’ socket can be used to save the results to CSV file.

SVF Node

Sky View Factor Node

An example analysis with a 3D city model of the Hague in the Netherlands can be seen below.

SVF analysis

Sky View Factor analysis of the Hague. Model provided courtesy of Filip Biljecki.


VI-Suite v0.4 – Radiance Patterns

As of version 0.4.7 the VI-Suite can now use Blender’s UV image mapping system to create image based Radiance patterns. In the example Radiance rendering below an image texture has been mapped to the wall and picture to create a diffuse reflecting Radiance image pattern, and to the window to create a transparent one.

The video tutorial below details the process.

VI-Suite v0.3 – Exporting LiVi Data

A user asked me how to export the x, y, z co-ordinates of the LiVi sensor positions with the results to a comma separated file for further plotting or analysis. This capability will be enabled in version 0.4 with the “Results out” socket of the LiVi simulation node, but for now you can copy the python code below into Blender’s text editor and press the “Run Script” button at the bottom of the text editor window. This code will export the currently visualised results for the current frame to files in the project directory. These files are named ‘name_of_results_object.manualres’.

LiVi results data is stored within the mesh’s vertices and faces. To do this LiVi uses Blender’s Bmesh wrapper for the mesh data. So the first part of the code loops through results objects (line 3) creates a bmesh representation of each one (line 5) and transforms the bmesh (line 6) so that vertex and space positions are in global or world co-ordinates.

Line 7 designates either vertices or faces as the results points depending on the object ‘cpoint’ property (which is created on LiVi geometry export). Line 8 then checks that there are results available in the mesh and line 9 defines the cindex layer which stores whether a point in a mesh is a results point. Line 10 defines the resl layer which actually holds the results.

Line 11 generates the vertex or face positions for each results point and stores them in the variable posis. Line 12 and 13 then define the output file and writes the co-ordinates and the data to the file. The final line 14 clears the bmesh data from memory.

import bpy, bmesh, os
scene = bpy.context.scene
for o in [o for o in if o.type == 'MESH' and o.get('cpoint') and o.lires]:
    bm =
    geom = bm.verts if o['cpoint'] == '1' else bm.faces
    if geom.layers.float.get('res{}'.format(scene.frame_current)) and'cindex'):
        cindex =['cindex']
        resl = geom.layers.float['res{}'.format(scene.frame_current)]
        posis = [ for v in bm.verts if v[cindex] > 0] if o['cpoint'] == '1' else [f.calc_center_bounds() for f in bm.faces if f[cindex] > 0]
        with open(os.path.join(scene['viparams']['newdir'], '{}.manualres'.format(, 'w') as resfile:
            resfile.write('\n'.join(['{0[0]}, {0[1]}, {0[2]}, {1}'.format(posis[gi], g[resl]) for gi, g in enumerate(geom) if g[cindex] > 0]))

Indentation in Python is important so make sure the code in the Blender Text editor window looks like the screenshot below.