©Anton Podvalny

Table of Contents


Introduction


V-Ray Fur is a very simple procedural fur plugin. The fur is generated only during render time and is not actually present in the scene.


 


Parameters


V-Ray Fur is implemented in the GeomHair plugin, which has a lot of parameters. They are the following:

Main

  • mesh - The triangle mesh that will have hairs generated on it.
  • length_base - The base length of the fur strands.
  • thickness_base - The base thickness of the strands.
  • gravity_base - This controls the force that pulls fur strands down along the direction of the gravity_vector.
  • gravity_vector - The gravity force direction vector.
  • bend - this parameter controls the elasticity of the fur strands. When it is 0.0, the strands are hard and are all straight lines. Greater values cause the strands to bend (e.g. under the influence of gravity).
  • taper - Allows you to add a taper to the individual strands of fur. Increasing this value will make each strand thinner in its upper end and wider in its base.
  • mtlID - Material ID of the faces of the mesh. This is only valid if the placement is by material ID. This is useful for applying a Multi/Sub-object material to the fur.


Geometric Detail

  • hair_sides - Number of segments along the circumference of a single hair.
  • hair_knots - Number of segments along the length of a single hair.
  • flat_normals - when this option is on, the normal of the fur strands does not vary across the strand width. Although not very precise, this is similar to how other fur/hair solutions work. It may also help with fur antialiasing, making the job of the image sampler a little easier. When this option is turned off, the surface normal varies across the width of the strands, creating the illusion that the strands have a cylindrical shape.
  • lod_enabled - Level of detail toggle. when this option is enabled, V-Ray will generate less fur geometry for parts of the scene which are far away from the camera. This is done by decreasing the density of the fur strands and increasi
  • lod_startDistance - Level of detail starting distance. The distance from the camera at which V-Ray is going to start implementing the level of detail adjustment. Up to this distance the fur will be generated as specified by the user, after that V-Ray is going to decrease the density and increase the thickness of the strand by a factor of two for every n unit of space specified by the Rate parameter.
  • lod_rate - Level of detail rate. The rate at which the detail adjustment is applied. Starting from the distance specified in the Start distance parameter V-Ray is going to decrease the density and increase the thickness of the strands by a factor of two for every n units of space specified by the Rate parameter.


Variation

For all of the following values are from 0.0 (no variation) to 1.0.

  • dir_var - The direction variation. This parameter adds slight variation to the direction in which fur strands grow from the source object. Any positive value is valid. This parameter should also depend on the scene scale.
  • length_var - The hair length variation.
  • thickness_var - The hair thickness variation.
  • gravity_var - The gravity variation.
  • curl_radius_var - The curl radius variation.


Distribution

  • distribution - determines the density of strands over the source object:

    • 0 - per face - specifies the number of fur strands per face of the source object. Every face will generate the specified number of fur strands.
    • 1 - per area - the number of strands per squared scene unit. For example, if the the system units are in meters, this parameter specifies the desired number of strands per square meter; if the system units are centimeters, it specifies the number of strands per square centimeter and so on. The area of the triangle faces (which is used to compute the number of strands for each face) is taken at the frame, specified by the Reference frame parameter. Every triangle face has at least one strand.
  • perFace - Number of hairs per face if distribution=0

  • perArea - Number of hairs per unit area if distribution=1


Placement

  • placement - The type of placement of the fur on the mesh. The possible values are:

    • 0 - Entire Object - all faces will generate fur.
    • 1 - Selected Faces - only selected faces (for example with a MeshSelect modifier) will generate fur.
    • 2 - Material ID - only faces with the specified material ID will generate fur.
  • faceList - A list of face indices that will have hair generated on them. If NULL all faces will have hair on them.

  • fixed_areas - True if areaList should be used to determine the number of hairs when distribution is 'per area'.
  • areaList - A list of triangle surface areas. An element here corresponds to an element in faceList, if faceList is not NULL.


Mapping

  • generate_w_coord - If true, V-Ray will generate a W mapping coordinate that represents the position of the shaded point along the hair strands. In general, all mapping coordinates are taken from the base object. However, the W mapping coordinate can be modified to represent the offset along the hair strands. When this option is on, the W coordinate is the offset along the hair strands (0.0 is the strand base, and 1.0 is the tip). The U and V coordinates are still taken from the base object.
  • map_channel - the channel for which the W coordinate will be modified, when the Generate W-coordinate option is on.


Others

  • curl_enabled - True if curl should be applied to the hair.
  • curl_angle - The angle of the curl applied at each knot.
  • curl_radius - The radius of the curls.
  • override_mtlID_on - Material ID will be overridden.
  • override_mtlID - The override material ID.
  • ignore_base_mesh_displacement - If false, fur will be displaced by using the parent mesh displacement map.
  • scale - Fur scaling factor.


Maps

You can control some aspects of GeomHair with texture maps. These can be either bitmaps, or vertex color maps painted directly on the source object.

  • bend_direction_tex - This is an RGB map which specifies a bend direction of the fur strands, in texture space (according to the specified Base map channel). This is the direction in which the fur strands curve to (the amount of curvature is also controlled by the Bend parameter). The red component is offset along the u texture direction, the green component is the offset along the v texture direction, and the blue component is the offset along the surface normal.
  • initial_direction_tex - This is an RGB map which specifies the initial direction of the fur strands, in texture space (according to the specified Base map channel). The red component is offset along the u texture direction, the green component is the offset along the v texture direction, and the blue component is the offset along the surface normal.


The following maps are multipliers for the corresponding parameters, where black is a multiplier of 0.0, and white is a multiplier of 1.0.

  • length_tex - A texture for the length.
  • thickness_tex - A texture for the thickness.
  • gravity_tex - A texture for the gravity.
  • bend_tex - A texture for the bend.

  • density_tex - this map is a multiplier for the strand density. Black portions of the map correspond to zero density (effectively no fur will be generated in these areas), and white represents the normal strand density, as specified by the distribution parameters.

  • curl_tex - A texture for the curls.


Code example


# The directory containing the vray shared object should be present in the PYTHONPATH environment variable.
# Try to import the vray module from VRAY_SDK/python, if it is not in PYTHONPATH
import sys, os
VRAY_SDK = os.environ.get('VRAY_SDK')
if VRAY_SDK:
    sys.path.append(os.path.join(VRAY_SDK, 'python'))
import vray

SCENE_PATH = os.path.join(os.environ.get('VRAY_SDK'), 'scenes')
# Change process working directory to SCENE_PATH in order to be able to load relative scene resources.
os.chdir(SCENE_PATH)

# Create an instance of VRayRenderer with default options.
# The renderer is automatically closed after the `with` block.
with vray.VRayRenderer() as renderer:
    # Register a simple log callback. Always useful for debugging.
    def dumpMsg(renderer, message, level, instant):
        if level == vray.LOGLEVEL_ERROR:
            print("[ERROR]", message)
        elif level == vray.LOGLEVEL_WARNING:
            print("[Warning]", message)
        elif level == vray.LOGLEVEL_INFO:
            print("[info]", message)
        # Uncomment for testing, but you might want to ignore these in real code
        #else: print("[debug]", message)
    renderer.setOnLogMessage(dumpMsg)
    # Load scene from a file.
    renderer.load(os.path.join(SCENE_PATH, 'cornell_new.vrscene'))
    # A reference to the Node plugin of one of the spheres in the scene
    sphereNode = renderer.plugins['Sphere0Shape2@node']
    # Create a GeomHair plugin
    # It References another mesh plugin (usually GeomStaticMesh) and generates hair (can be tweaked for fur, grass, shaggy rug etc.) on it.
    # Has many parameters for the size, shape and distribution of strands.
    hairMesh = renderer.classes.GeomHair()
    hairMesh.mesh = sphereNode.geometry                    # Attach a geometry to the hair
    hairMesh.length_base = 20                              # The base hair length.
    hairMesh.length_var = 5                                # The hair length variation.
    hairMesh.thickness_base = 0.2                          # The base hair thickness.
    hairMesh.thickness_var = 0.1                           # The hair thickness variation.
    hairMesh.curl_enabled = True                           # Apply curl to the hair
    hairMesh.curl_radius_var = 20                          # The curl radius variation.
    hairMesh.curl_angle = 20                               # The angle of the curl applied at each knot. (degrees)
    hairMesh.hair_knots = 20                               # Number of segments along the length of a single hair.
    hairMesh.bend = 0.25                                   # The amount of hair bending. (relative)
    hairMesh.perFace = 20                                  # Number of hairs per face with the default distribution value
    hairMesh.gravity_vector = vray.Vector(0.0, 0.0, -1.0)  # The gravity force direction vector.
    # Create a new hair BRDF plugin instance and set several parameters.
    hairBrdf = renderer.classes.BRDFHair3()
    hairBrdf.diffuse_color = vray.AColor(0.1, 0.05, 0.025, 1)
    hairBrdf.primary_specular = vray.AColor(0.7, 0.6, 0.5, 1)
    hairBrdf.secondary_specular = vray.AColor(0.3, 0.2, 0.1, 1)
    hairBrdf.transmission = vray.AColor(0.3, 0.2, 0.1, 1)
    hairBrdf.transmission_glossiness_length = 0.5
    hairBrdf.transmission_glossiness_width = 0.5
    # Create a new material plugin instance using the hair BRDF.
    hairMaterial = renderer.classes.MtlSingleBRDF()
    hairMaterial.brdf = hairBrdf
    # Create a node for the GeomHair
    hairNode = renderer.classes.Node()
    # The GeomHair should be attached just as a usual geometry to the node
    hairNode.geometry = hairMesh
    hairNode.material = hairMaterial
    hairNode.transform = sphereNode.transform
    # Start rendering.
    renderer.startSync()
    # Wait for rendering to end.
    renderer.waitForRenderEnd()
#define VRAY_RUNTIME_LOAD_PRIMARY
#include "vraysdk.hpp"
#include "vrayplugins.hpp"
#include "utils.h"

using namespace VRay;
using namespace VRay::Plugins;
using namespace std;

const char* BASE_PATH = getenv("VRAY_SDK");
string SCENE_PATH = (BASE_PATH ? string(BASE_PATH) : string(".")) + PATH_DELIMITER + "scenes";

int main() {
	// Change process working directory to SCENE_PATH in order to be able to load relative scene resources.
	changeCurrentDir(SCENE_PATH.c_str());
	// Load V-Ray SDK library.
	VRayInit init(NULL, true);
	// Create an instance of VRayRenderer with default options.
	// The renderer is automatically closed at the end of the current scope.
	VRayRenderer renderer;
	// It's recommended to always have a console log
	renderer.setOnLogMessage(logMessage);
	// Load scene from a file.
	renderer.load("cornell_new.vrscene");
	// A reference to the Node plugin of one of the spheres in the scene
	Node sphereNode = renderer.getPlugin<Node>("Sphere0Shape2@node");
	// Create a GeomHair plugin
	// It References another mesh plugin (usually GeomStaticMesh) and generates hair (can be tweaked for fur, grass, shaggy rug etc.) on it.
	// Has many parameters for the size, shape and distribution of strands.
	GeomHair hairMesh = renderer.newPlugin<GeomHair>();
	hairMesh.set_mesh(sphereNode.get_geometry());         // Attach a geometry to the hair
	hairMesh.set_length_base(20);                         // The base hair length.
	hairMesh.set_length_var(5);                           // The hair length variation.
	hairMesh.set_thickness_base(0.2f);                    // The base hair thickness.
	hairMesh.set_thickness_var(0.1f);                     // The hair thickness variation.
	hairMesh.set_curl_enabled(true);                      // Apply curl to the hair
	hairMesh.set_curl_radius_var(20);                     // The curl radius variation.
	hairMesh.set_curl_angle(20);                          // The angle of the curl applied at each knot. (degrees)
	hairMesh.set_hair_knots(20);                          // Number of segments along the length of a single hair.
	hairMesh.set_bend(0.25f);                             // The amount of hair bending. (relative)
	hairMesh.set_perFace(20);                             // Number of hairs per face with the default distribution value
	hairMesh.set_gravity_vector(Vector(0.0, 0.0, -1.0));  // The gravity force direction vector.
	// Create a new hair BRDF plugin instance and set several parameters.
	BRDFHair3 hairBrdf = renderer.newPlugin<BRDFHair3>();
	hairBrdf.set_diffuse_color(AColor(0.1, 0.05, 0.025, 1));
	hairBrdf.set_primary_specular(AColor(0.7, 0.6, 0.5, 1));
	hairBrdf.set_secondary_specular(AColor(0.3, 0.2, 0.1, 1));
	hairBrdf.set_transmission(AColor(0.3, 0.2, 0.1, 1));
	hairBrdf.set_transmission_glossiness_length(0.5);
	hairBrdf.set_transmission_glossiness_width(0.5);
	// Create a new material plugin instance using the hair BRDF.
	MtlSingleBRDF hairMaterial = renderer.newPlugin<MtlSingleBRDF>();
	hairMaterial.set_brdf(hairBrdf);
	// Create a node for the GeomHair
	Node hairNode = renderer.newPlugin<Node>();
	// The GeomHair should be attached just as a usual geometry to the node
	hairNode.set_geometry(hairMesh);
	hairNode.set_material(hairMaterial);
	hairNode.set_transform(sphereNode.get_transform());
	// Start rendering.
	renderer.startSync();
	// Wait for rendering to end.
	renderer.waitForRenderEnd();
	return 0;
}
using System;
using System.IO;
using VRay;
using VRay.Plugins;

namespace _geom_hair
{
	class Program
	{
		static void Main(string[] args)
		{
			string SCENE_PATH = Path.Combine(Environment.GetEnvironmentVariable("VRAY_SDK"), "scenes");
			// Change process working directory to SCENE_PATH in order to be able to load relative scene resources.
			Directory.SetCurrentDirectory(SCENE_PATH);
			// Create an instance of VRayRenderer with default options. The renderer is automatically closed after the `using` block.
			using (VRayRenderer renderer = new VRayRenderer())
			{
				// Add a listener for any type of log message.
				renderer.LogMessage += new EventHandler<MessageEventArgs>((source, e) =>
				{
					// You can remove the if for testing, but you might want to ignore Debug in real code
					if (e.LogLevel != LogLevelType.Debug)
					{
						Console.WriteLine(String.Format("[{0}] {1}", e.LogLevel.ToString(), e.Message));
					}
				});
				// Load scene from a file.
				renderer.Load("cornell_new.vrscene");
				// A reference to the Node plugin of one of the spheres in the scene
				Node sphereNode = renderer.GetPlugin<Node>("Sphere0Shape2@node");
				// Create a GeomHair plugin
				// It References another mesh plugin (usually GeomStaticMesh) and generates hair (can be tweaked for fur, grass, shaggy rug etc.) on it.
				// Has many parameters for the size, shape and distribution of strands.
				GeomHair hairMesh = renderer.NewPlugin<GeomHair>();
				hairMesh.Mesh = sphereNode.Geometry;                  // Attach a geometry to the hair
				hairMesh.LengthBase = 20;                             // The base hair length.
				hairMesh.LengthVar = 5;                               // The hair length variation.
				hairMesh.ThicknessBase = 0.2f;                        // The base hair thickness.
				hairMesh.ThicknessVar = 0.1f;                         // The hair thickness variation.
				hairMesh.CurlEnabled = true;                          // Apply curl to the hair
				hairMesh.CurlRadiusVar = 20;                          // The curl radius variation.
				hairMesh.CurlAngle = 20;                              // The angle of the curl applied at each knot. (degrees)
				hairMesh.HairKnots = 20;                              // Number of segments along the length of a single hair.
				hairMesh.Bend = 0.25f;                                // The amount of hair bending. (relative)
				hairMesh.PerFace = 20;                                // Number of hairs per face with the default distribution value
				hairMesh.GravityVector = new Vector(0.0, 0.0, -1.0);  // The gravity force direction vector.
				// Create a new hair BRDF plugin instance and set several parameters.
				BRDFHair3 hairBrdf = renderer.NewPlugin<BRDFHair3>();
				hairBrdf.DiffuseColor = new AColor(0.1, 0.05, 0.025, 1);
				hairBrdf.PrimarySpecular = new AColor(0.7, 0.6, 0.5, 1);
				hairBrdf.SecondarySpecular = new AColor(0.3, 0.2, 0.1, 1);
				hairBrdf.Transmission = new AColor(0.3, 0.2, 0.1, 1);
				hairBrdf.TransmissionGlossinessLength = 0.5;
				hairBrdf.TransmissionGlossinessWidth = 0.5;
				// Create a new material plugin instance using the hair BRDF.
				MtlSingleBRDF hairMaterial = renderer.NewPlugin<MtlSingleBRDF>();
				hairMaterial.Brdf = hairBrdf;
				// Create a node for the GeomHair
				Node hairNode = renderer.NewPlugin<Node>();
				// The GeomHair should be attached just as a usual geometry to the node
				hairNode.Geometry = hairMesh;
				hairNode.Material = hairMaterial;
				hairNode.Transform = sphereNode.Transform;
				// Start rendering.
				renderer.StartSync();
				// Wait for rendering to end.
				renderer.WaitForRenderEnd();
			}
		}
	}
}
var path = require('path');
var vray = require(path.join(process.env.VRAY_SDK, 'node', 'vray'));

var SCENE_PATH = path.join(process.env.VRAY_SDK, 'scenes');
// Change process working directory to SCENE_PATH in order to be able to load relative scene resources.
process.chdir(SCENE_PATH);

// Create an instance of VRayRenderer with default options.
var renderer = vray.VRayRenderer();
// It's recommended to always have a console log callback
renderer.on("logMessage", function(message, level, instant) {
	if (level == vray.LOGLEVEL_ERROR)
		console.log("[ERROR] ", message);
	else if (level == vray.LOGLEVEL_WARNING)
		console.log("[Warning] ", message);
	else if (level == vray.LOGLEVEL_INFO)
		console.log("[info] ", message);
	// Uncomment for testing, but you might want to ignore these in real code
	//else console.log("[debug] ", message);
});
// Load scene from a file asynchronously.
renderer.load("cornell_new.vrscene", function(err) {
	if (err) throw err;
	// A reference to the Node plugin of one of the spheres in the scene
	var sphereNode = renderer.plugins["Sphere0Shape2@node"];
	// Create a GeomHair plugin
	// It References another mesh plugin (usually GeomStaticMesh) and generates hair (can be tweaked for fur, grass, shaggy rug etc.) on it.
	// Has many parameters for the size, shape and distribution of strands.
	var hairMesh = renderer.classes.GeomHair();
	hairMesh.mesh = sphereNode.geometry;                    // Attach a geometry to the hair
	hairMesh.length_base = 20;                              // The base hair length.
	hairMesh.length_var = 5;                                // The hair length variation.
	hairMesh.thickness_base = 0.2;                          // The base hair thickness.
	hairMesh.thickness_var = 0.1;                           // The hair thickness variation.
	hairMesh.curl_enabled = true;                           // Apply curl to the hair
	hairMesh.curl_radius_var = 20;                          // The curl radius variation.
	hairMesh.curl_angle = 20;                               // The angle of the curl applied at each knot. (degrees)
	hairMesh.hair_knots = 20;                               // Number of segments along the length of a single hair.
	hairMesh.bend = 0.25;                                   // The amount of hair bending. (relative)
	hairMesh.perFace = 20;                                  // Number of hairs per face with the default distribution value
	hairMesh.gravity_vector = vray.Vector(0.0, 0.0, -1.0);  // The gravity force direction vector.
	// Create a new hair BRDF plugin instance and set several parameters.
	var hairBrdf = renderer.classes.BRDFHair3();
	hairBrdf.diffuse_color = vray.AColor(0.1, 0.05, 0.025, 1);
	hairBrdf.primary_specular = vray.AColor(0.7, 0.6, 0.5, 1);
	hairBrdf.secondary_specular = vray.AColor(0.3, 0.2, 0.1, 1);
	hairBrdf.transmission = vray.AColor(0.3, 0.2, 0.1, 1);
	hairBrdf.transmission_glossiness_length = 0.5;
	hairBrdf.transmission_glossiness_width = 0.5;
	// Create a new material plugin instance using the hair BRDF.
	var hairMaterial = renderer.classes.MtlSingleBRDF();
	hairMaterial.brdf = hairBrdf;
	// Create a node for the GeomHair
	var hairNode = renderer.classes.Node();
	// The GeomHair should be attached just as a usual geometry to the node
	hairNode.geometry = hairMesh;
	hairNode.material = hairMaterial;
	hairNode.transform = sphereNode.transform;
	// Start rendering.
	renderer.start(function(err) {
		if (err) throw err;
		// Wait for rendering to end.
		renderer.waitForRenderEnd(function() {
			// Closes the renderer.
			renderer.close();
		});
	});
});


Example


The following grass-like effect is created using the V-Ray Procedural fur using this scene.



Notes


  • Avoid applying textures with Object XYZ mapping to the fur. If you need to use a 3d procedural texture, apply a UVW Map modifier to the source object with the option to convert XYZ to UVW coordinates and use explicit mapping for the texture.
  • Avoid having very large triangles covered with fur, since the fur is generated in groups corresponding to triangles of the original mesh.
  • Shadow maps will not include information about the GeomHair. However, other objects will cast shadows on the fur, even with shadow maps.
  • Sharp Shadows may produce flickering with GeomHair in animations, because the lighting situation of individual hairs will change very rapidly. Area shadows or VRayLights may produce smoother results.
  • GeomHair will not work with Infinite Plane | GeomInfinitePlane as a base object.
  • No labels