Generate floor boards quick and easy, part II

In a previous article I presented a simple script to generate floor boards with real geometry. Since then I enhanced this with an option to generate uv coordinates as well, with a random offset for each individual plank. This option not only relieves the user of the need to create a uv map but the random offset will break the unwanted illusion that all planks are perfectly sawn from a single endless pices of wood.

The image in the example on the left (click to enlarge) was generated with the wood shader presented earlier but similar effects can be obtained by applying a tiled image (which of course should not depict planks already), for example PlywoodNew0050 from CGTextures would work nicely I think.

The updated script (version 0.0.3) is available from GitHub and is tracked in the Blender Bug Tracker as well. Version 0.0.3 also has its hard limits on plank length etc. removed. The are replaced by soft limits so if you want you can make planks shorter than 50cm or narrower than 10cm by explicitly typing in a value.

A new tree addon part VII: tweaking leaf UVs

Now that the addon is in Blender's Contrib repository I thought it was time to start acting on some of the feedback from the BlenderArtists thread.

This release contains two minor improvements:

  • rotated UV-maps for the leaves and
  • an option to set the offset of the leaves from the twigs
Previously the UV-maps that were generated for the leaves were rotated. Because most alpha mapped leaf image textures feature leaves with the tip at the top and the stem at the bottom this rotated arrangement was often counter intuitive.

Depending on the image that you use as a leaf texture it might be useful to be able to control the point where the leaves are joined to the twig. This offset is now provided as an option slider in the leaves section. Note that even if this offset is zero the leaf plane might still be intersected by a twig. This happens when the branches are skinned with Blender's skin modifier (instead of the native skinning method).Before this skin modifier the addon adds a subsurface modifier which has the effect of cutting corners. Choosing a smaller internode distance and removing this subsurface modifier will prevent this unwanted intersection but in most cases (I.e. with enough leaves) this probably won't be noticeable anyway.

Book review: Blender 2.6 Cycles: Materials and textures cookbook

Last week I had the opportunity to read the Cycles materials and textures cookbook and it proved to be a worthwhile read.

The author, Enrico Valenza, is an experienced and professional Blender user so a book by him is certainly worth checking out. The book presents some thirty shaders in a cookbook style and offers many insights in the Cycles rendering system not limited to specific materials. Although a cookbook implies that you can use the recipes as they are presented, the techniques that are offered in the book will get you a lot further than that and will help you develop skills necessary to develop your own materials because of the very detailed way their implementation is described.

pros

thorough,
each material is described in step-by-step detail and pretty much every avaible Cycles node is featured somewhere and both node groups and frames are covered as well,
comprehensive,
both materials based on textures and materials based on procedural noise are covered and the all important concept of layering increasingly fine detail to get realistic textures is featured quite some times,
interesting
some materials feature mainly as a means to illustrate a concept but many materials are quite good and some are even excellent, my favorites are the sponge texture, the leather texture and the ancient bronze texture.

cons

  • the introductory chapter on how to set up Cycles and where to find stuff isn't all that clear. This isn't necessarily the author's fault because sometimes the Blender interface can be overwhelming. Maybe this is one of those situations where a video tutorial is useful,
  • the resolution of the illustrations is way to low. If you try to zoom in the lettering of the node labels isn't readable. And yes, high resolution versions of those illustrations are available for download but that detracts from the reading experience a lot.

Conclusion

Nice and thorough book to get you started on creating materials for Cycles, the e-book versions are certainly worth your money in my opinion (personally i think that twice the price for a print version is over the top but of course there will always be people who prefer the genuine touch of paper :-)

Generate floor boards quick and simple

I am updating this addon, check for an update this article.

I am currently enrolled in Andrew Price's Architecture Academy and in one of his tutorials he mentioned how easy it would be to have a simple script that could create floor boards suitable for architectural renders like those available in some other modelling packages. He even thought about asking someone to develop it but for some reason or other it never came te be.

Add Floor Boards

Because I think it would make a useful addition to the ArchViz' modeller 's tool set I put together a simple script Add Floor Boards. Once installed it can be found in the Add->Mesh menu at the to of the 3D view. Slap on a decent wood shader and you have a floor with real geometry in a few seconds.

The object that is generated by the script is a simple collection of rectangular faces adorned with a solidify and a bevel modifier so you can tweak some stuff even after the tool properties are no longer accessible.

Installation

  • Download the script from GitHub
  • Click File->User Preferences->Addons and click the install script from file
  • Don't forget to enable the add-on, it can be found in the Add Mesh section

Usage

After clicking Add->Mesh->Add Floor Board a default floor board is generated. The tool options should be self explanatory and are shown below:

Note that the measures are in blender units and the defaults reflect typical oak boards available at my local floor board dealer and are denoted in meters. (If you do archviz work it makes sense tp select some units in the scene options). Note that the variations in length and width are added to the base measurements so set them to zero if you want comlletely regular planks (a fixed width is quite common, a fixed length not so much as it leads to waste).

Blender addon to setup image based lighting (IBL) nodes in Cycles

setting up image based lighting (IBL) in Cycles isn't all that difficult but creating a versatile setup requires a lot of repetitive actions that lends itself well to automation. In this article I present a simple add-on that may be accessed from the Add menu in the node editor to quickly set up all the nodes for environment lighting.
Note: as of 2015/03/13 a bug fix release is available on GitHub.

The SIBL archive

One of the resources I find myself using quite often is the SIBL archive. Each archive is basically a directory (commonly packed as a .zip file) that contains both a high resolution backplate and HDR environment and reflection maps. It also contains an .ibl file that documents the resources available in the .zip file. The add-on uses this .ibl file to create all necessary nodes and references to the images. I am not sure how widely accepted the SIBL format is, but the add-on can also be used by simply selecting a .jpg and a .hdr file instead of a .ibl file so you are not restricted to just SIBL files.

Installation


Download the add-on
It is available on Github as a single file sibl.py. You can directly save it to your download directory via this link.
Install in Blender
Open the add-ons section of Blenders User Preferences and click Add external add-on. Select the downloaded file and click install. After installation you may find it in the Node section where you can activate it.

Usage

With a SIBL archive

Enable the add-on
In the add-ons section of the user preferences. It sits in the Node category.
Download a SIBL archive
Unzip the archive
Go to the World nodes
Click the world icon in the node editor.
Click Add -> Sibl Environment Setup
Select the .ibl file
Click Add Environment

With separate files

Enable the add-on
In the add-ons section of the user preferences. It sits in the Node category.
Go to the World nodes
Click the world icon in the node //editor.
Click Add -> General Environment Setup
Select one or two files
If you select more than one file, a file with a .hdr extension will be used as the environment lighting and the other one as the backplate.
Click Add Environment
After selecting the files the node setup will be displayed in the node editor. If there were any issues with the .hdr or backplate images the corresponding environment texture node is colored red. This may happen if the file is unreadable for some reason or if the the .ibl file points to non existing files.

Options

When the file selector is opened to allow you to select a file, some options are available in a panel on the left of the list of files:
Use reflection map
This one is only present when opening a .ibl file. It selects a higher resolution environment map suitable for glossy reflections (if available). You probably should only use this if you want to see the environment reflected in glossy surfaces because a reflection .hdr uses a lot more memory than a low resolution .hdr environment map.
Clear node tree
Uncheck this if you want to keep any existing nodes in the world node tree. If unchecked a world output node will be reused if present, as are any texture coordinate and light path nodes. Other nodes are untouched.

Implementation details

While developing this add-on I noticed that the [Environment] section in some .ibl files was spelled without an n. This is probably a bug but this add-on accepts both spellings. (An .ibl file is formatted as an .ini file, a common file format on windows and easily parsable with Python's configparser module.
All meta-data in .ibl files is ignored. This means any sun or additional key lights defined in the file are ignored. Also, all image files are currently assumed to be spherical (a.k.a. equirectangular or LatLong format, Blender's default mapping for environment textures). This means that light probe maps are currently not supported.

An OSL wood shader with knots for Blender Cycles

In a previous article I presented a shader that could be used to create the impression of knots in wood. This was accomplished by warping the texture coordinates around randomly distributed points in space.

Knots however do not resemble spheres but are more like cylinders that are cut under a slight angle. This distinction is not that important but for completeness sake we present this new implementation here together with a node setup that combines these knots with the wood shader we presented a while ago. An example result is shown below.

Code and example node setup

The implementation differs from the previous one in generating random lines (represented by a random point plus a random direction) instead of points. The texture coordinates are bent proportional to the distance to the closest point on this random line, so the bend() is a little bit more complicated than before.


vector random_sphere(point p, int n, float zdistribution){
float t = M_2PI*noise("cell",p,n*2+0);
float u = 2*noise("cell",p,n*2+1)-1;
float s,c,a;
sincos(t,s,c);
a = sqrt(1-u*u);
float x = a*c;
float y = a*s;
float z = u*zdistribution;
return vector(x,y,z);
}

int bend(vector p, vector k, vector kv, float r, float a, float m, output vector B){
vector pk = k - p;
vector t = dot(pk,kv)/dot(kv,kv);
vector D = k + t * kv - p;
float L = length(D);
if( L < r ){
float c = L/r;
float d = m * pow( 1 - c , a);
if( d < L ){
B = d * normalize(D);
return 1;
}else{
B = D;
return 2;
}
}
return 0;
}

shader knot(
vector Pos = P,
float Scale = 1.5,

float R = 2.9,
float Falloff = 2,
float Strength = 1,
float Knots=0.1,
float Z=1,

output vector Vec = P,
output float Fac = 0
){
vector p = Scale * Pos;
vector sdp = 0;

float TR = ceil(R);
for(float dx=-TR; dx <= TR; dx++){
for(float dy=-TR; dy <= TR; dy++){
for(float dz=-TR; dz <= TR; dz++){
vector ip = floor(p)+vector(dx,dy,dz);
for(int ik=0; ik < (int)Knots; ik++){
vector k = noise("cell",ip,ik);
vector kv= random_sphere(ip,ik+1000,Z);
vector dp= 0;
int ret = bend(p,ip+k,kv,R,Falloff,Strength,dp);
if(ret != 0){
Fac=max(Fac,ret==2);
sdp+=dp;
}
}
if( noise("cell",ip,-1) < mod(Knots,1.0) ){
vector k = noise("cell",ip,-2);
vector kv= random_sphere(ip,998,Z);
vector dp= 0;
int ret = bend(p,ip+k,kv,R,Falloff,Strength,dp);
if(ret != 0){
Fac=max(Fac,ret==2);
sdp+=dp;
}
}
}
}
}
if( Fac < 1 ){
Vec = p + sdp;
}else{
Vec = sdp;
}
}
Note that the function random_sphere() is modified from the one presented in a previous article to bias the vectors that are returned. This allows us to tweak the orientation of the generated knots, which might give more realisted results because branches (the source of the knots) are not pointing in all directions from the stem.

The node setup used to create the material in the example image is shown below (click to enlarge).

Room for improvement

The distribution of the knots might be convincing enough for our purposes but the material is now just another (darker) wood mzterial, rings and all. Quits a number of wood knots do look like that but a significant fraction shows characteristic radial cracks. This is caused when the wood is dried because the material properties of the knot are different from the surrounding wood. It would be nice if we could implement this in some way as well.

Random points on a unit sphere in OSL, code and benchmarks

In preparation to adapting the wood knot shader to have randomly oriented cylindrical knots rather than spherical knots I needed a function that generates vectors that are uniformly distributed over the surface of a unit sphere. This is not as simple as creating a vector with three random components but several methods exist that will produce vectors with a correct distribution.

A straight forward method (implemented in the function random_sphere() shown below) consists of generating correctly distributed spherical coordinates and the converting them to cartesian coordinates. This works fine but because trigonometric functions (like acos() and sincos()) used here) may be expensive, several alternatives exist that do not use these functions.

In the code presented here we have implemented the methods of Marsaglia (random_sphere1()) and Cook (random_sphere2()). Both are rejection methods: they discard some random numbers when they would lead to invalid vectors. This is wasteful so the question is: are these methods really more efficient on modern hardware where trigonometric functions are implemented as cpu operations?

Some timings

The timings presented below were measured on a 64-bit Amd 6-core cpu with the shader provided below. They might be completely different for other CPUs and probably even more so once OSL shaders will be able to run on a GPU.

nrandom_sphererandom_sphere1 random_sphere2
100 3.6 3.4 7.5
500 10.4 10.1 -
First thing to note is that the timings for 100 and 500 vectors do not scale proportionally because some of the dots we draw with our shader overlap, effectively reducing the number of vectors we have to generate for each shading sample. The other thing is that random_sphere2 is much slower than the other implementations, probably because we generate more random numbers and reject a lot more combinations.

As for the difference between the other two methods: the difference is probably significant but too small to make a real difference on my CPU. I'll probably check again when I get another CPU or OSL shaders will run on a GPU, but for now I stick with the most straightforward method.

Code and node setup


// generate random unit vectors randomly distributed over a sphere
// straight forward method
vector random_sphere(point p, int n){
float t = M_2PI*noise("cell",p,n*2+0);
float u = 2*noise("cell",p,n*2+1)-1;
float s,c,a;
sincos(t,s,c);
a = sqrt(1-u*u);
float x = a*c;
float y = a*s;
float z = u;
return vector(x,y,z);
}

// marsaglia's method
vector random_sphere1(point p, int m){
vector v = 0;
float repeat = 0;
int n = m + 1;
while(1){
repeat++;
float r0 = 2*noise("cell",p,repeat*n*2+0)-1;
float r1 = 2*noise("cell",p,repeat*n*2+1)-1;
float r02 = r0*r0;
float r12 = r1*r1;
float sr2 = r02 + r12;
if( sr2 < 1 ){
float x = 2*r0*sqrt(1-r02-r12);
float y = 2*r1*sqrt(1-r02-r12);
float z = 1-2*sr2;
v = vector(x,y,z);
break;
}
}
return v;
}

// cook's method
vector random_sphere2(point p, int m){
vector v = 0;
float repeat = 0;
int n = m + 1;
while(1){
repeat++;
float r0 = 2*noise("cell",p,repeat*n*4+0)-1;
float r1 = 2*noise("cell",p,repeat*n*4+1)-1;
float r2 = 2*noise("cell",p,repeat*n*4+2)-1;
float r3 = 2*noise("cell",p,repeat*n*4+3)-1;
float r02 = r0*r0;
float r12 = r1*r1;
float r22 = r2*r2;
float r32 = r3*r3;
float sr2 = r02 + r12 + r22 + r32;
if( sr2 < 1 ){
float x = 2*(r1*r3 + r0*r2)/sr2;
float y = 2*(r2*r3 - r0*r1)/sr2;
float z = (r02 + r32 - r12 - r22)/sr2;
v = vector(x,y,z);
break;
}
}
return v;
}

shader sphere_test(
vector p = P,
int n = 100,
float R = 0.03,
int method = 0,

output float Fac = 0
){
for(int i=0; i < n; i++){
vector v = 0;
if( method == 0 ){
v= random_sphere(point(0,0,0),i);
}else if( method == 1){
v= random_sphere1(point(0,0,0),i);
}else{
v= random_sphere2(point(0,0,0),i);
}
if( distance(point(0,0,0),1000*v,p ) < R ){
Fac = 1;
break;
}
}
}

The way we generate random numbers might seem strange but not only do we want to be able to generate any number of vectors for a given cell but in the rejection methods we also want to be able to generate replacements that are guaranteed to be different, hence the multiplication by the number of times we have to repeat.

The image shows the node setup used to verify the shader and time the different implementtations