How do I get Advanced Wood map to work in Octane? Which projection to use to get this result?
https://youtu.be/vUpVdEANQ1U?si=gZlRmpFShhi6zBC2&t=151
Advanced wood.
If that texture node is not compatible (most likely), Octane has its own procedural wood texture.
The projection is entirely a case-by-case matter as it depends on the asset shape, presence or lack of UVs, etc.
When it comes to "producing believable results", there are many factors to consider which are outside the scope of this post but fall into "texture proceduralism" where any related resources such as from Substance Designer, Blender Nodevember and similar, would aid.

The projection is entirely a case-by-case matter as it depends on the asset shape, presence or lack of UVs, etc.
When it comes to "producing believable results", there are many factors to consider which are outside the scope of this post but fall into "texture proceduralism" where any related resources such as from Substance Designer, Blender Nodevember and similar, would aid.
Octane resources
OCTANE POSTS (URLs have changed, which will break some links but all content remains available).
OCTANE POSTS (URLs have changed, which will break some links but all content remains available).
Unfortunately Woodgrain is not even close to as good as Advanced Wood. Advanced Wood is made with OSL (AdvancedWood.osl attached). It would be great if Otoy could tweak OSL to make it work as well in Octane as it does in other renderers.
- Attachments
-
- AdvancedWood.osl
- (24.77 KiB) Downloaded 283 times
Many nodes in Octane are OSL based under the hood. In fact, WoodGrain is OSL as well, but indeedly not equal.
Technically speaking, anyone with OSL knowledge could adapt it since the OSL texture node in Octane is user-accessible (not necessarily requiring the intervention of the Octane dev-team).
For reference, OSL guide (last update: 2021) and some recent changes to OSL here and here (CTRL or CMD + F, "OSL").
At least, the compiling output no error.
The code of the OSL, same as the one uploaded (for reference):
Technically speaking, anyone with OSL knowledge could adapt it since the OSL texture node in Octane is user-accessible (not necessarily requiring the intervention of the Octane dev-team).
For reference, OSL guide (last update: 2021) and some recent changes to OSL here and here (CTRL or CMD + F, "OSL").
At least, the compiling output no error.
The code of the OSL, same as the one uploaded (for reference):
Code: Select all
//
// PRISM Wood material shader, based on the RTSL implementation by Karl Schmidt
// which in turn was based on work by Zhao Dong and Milos Hasan
// OSL port by Zap Andersson
//
// Modified: 2021-09-23
// Copyright 2021 Autodesk Inc, All rights reserved. This file is licensed under Apache 2.0 license
// https://github.com/ADN-DevTech/3dsMax-OSL-Shaders/blob/license/LICENSE.txt
//
///////////////////////////////////////////////////////////////////////////
// Constants
///////////////////////////////////////////////////////////////////////////
#include <vector4.h>
#define float4 vector4
#define PI 3.14159265
#define TWO_PI (2.0 * PI)
#define HALF_PI (0.5 * PI)
#define bool int
#define true 1
#define false 0
#define PERFECT_SPECULAR_ROUGNESS 0.001
#define WOOD_PORE_BOTH 0
#define WOOD_PORE_EARLY 1
#define WOOD_PORE_LATE 2
///////////////////////////////////////////////////////////////////////////
// Utility functions for RapidRT Prism shaders
///////////////////////////////////////////////////////////////////////////
float frac(float f)
{
return f - floor(f);
}
float saturate(float x)
{
return clamp(x,0.0,1.0);
}
float partialSmoothstep(float min, float max, float x){
float tmp = saturate((x - min) / (max - min));
if (tmp < 0.5) {
return tmp;
}
else {
return tmp*tmp*(3.0 - 2.0*tmp);
}
}
///////////////////////////////////////////////////////////////
// Shader /////////////////////////////////////////////////////
shader prism_wood
[[ string label = "Advanced Wood",
string version = "1.0.0",
string help = "<h3>Advanced Wood</h3>"
"This OSL shader is similar to the classic 'Advanced Wood', except the UVW "
"can be modified with external shaders, and a random seed can be driven "
"to have per-object variations.<br>"
"It is also fully supported in a 'High Quality' viewport and will<br>"
"render <i>exactly the same</i> on any OSL capable renderer."
]]
(
vector UVW = transform("object", P),
int Seed = 0,
//////////
// Wood //
//////////
float scale = 1.0 [[ string label = "Scale" ]],
int unit_dependent = 1 [[ string label = "Unit Dependent", string widget = "checkBox", int connectable = 0]],
int axis = 2 [[ string label = "Axis", string widget = "mapper", string options = "X:0|Y:1|Z:2", int connectable = 0]],
// Wood Seasonal Growth Params
float ring_thickness = 0.75 [[ string label = "Ring Thickness", float min = 0.01, float max = 1.0 ]],
float late_wood_ratio = 0.238 [[ string label = "Late Wood Ratio", float min = 0.0, float max = 1.0 ]],
float early_wood_sharpness = 0.395 [[ string label = "Early Wood Sharpness", int connectable = 0, float min = 0.0, float max = 1.0 ]],
float late_wood_sharpness = 0.109 [[ string label = "Late Wood Sharpness", int connectable = 0, float min = 0.0, float max = 1.0 ]],
// Wood Grain Color Params
color early_wood_color = color(0.2, 0.08, 0.024) [[ string label = "Early Wood Color" ]],
bool use_manual_late_wood_color = false [[ string label = "Use Manual Late Wood Color", string widget = "checkBox", int connectable = 0 ]],
color manual_late_wood_color = color(0.217, 0.071, 0.01) [[ string label = "Late Wood Color" ]],
float late_wood_color_power = 1.07 [[ string label = "Late Wood Color Power", float min = 0.01, float max = 5.0 ]],
// Wood Pores Params
bool use_pores = true [[ string label = "Use Pores", string widget = "checkBox", int connectable = 0 ]],
int pore_type = 0 [[ string label = "Pore Type", int connectable = 0, string widget="mapper", string options = "Both:0|Early Only:1|Late Only:2" ]],
float pore_cell_dim = 0.12 [[ string label = "Pore Cell Dim", int connectable = 0, float min = 0.01, float max = 3.0 ]],
float pore_radius = 0.04 [[ string label = "Pore Radius", int connectable = 0, float min = 0.01, float max = 2.0 ]],
float pore_color_power = 2.13 [[ string label = "Pore Color Power", float min = 0.01, float max = 5.0 ]],
float pore_depth = 0.01 [[ string label = "Pore Depth", int connectable = 0, float min = 0.0, float max = 1.0 ]],
// Wood Rays Params
bool use_rays = true [[ string label = "Use Rays", string widget = "checkBox", int connectable = 0 ]],
float ray_color_power = 1.1 [[ string label = "Ray Color Power", float min = 0.01, float max = 5.0 ]],
float ray_seg_length_z = 5.0 [[ string label = "Ray Seg Length Z", int connectable = 0, float min = 0.01, float max = 10.0 ]],
int ray_num_slices = 160 [[ string label = "Ray Num Slices", int connectable = 0, int min = 1, int max = 400 ]],
float ray_ellipse_depth = 2.0 [[ string label = "Ray Ellipse Depth", int connectable = 0, float min = 0.01, float max = 10.0 ]],
float ray_ellipse_scale_x = 0.2 [[ string label = "Ray Ellipse Scale Z", int connectable = 0, float min = 0.01, float max = 1.0 ]],
float ray_ellipse_z2x = 10.0 [[ string label = "Ray Ellipse Z2X", int connectable = 0, float min = 0.0, float max = 40.0 ]],
float ray_roughness = 0.1 [[ string label = "Ray Ellipse Roughness", int connectable = 0, float min = 0.0, float max = 1.0 ]],
float ray_bump_depth = 0.02 [[ string label = "Ray Ellipse Bump Depth", int connectable = 0, float min = 0.0, float max = 1.0 ]],
// Wood Shading Params
float roughness = 0.25 [[ string label = "Roughness", float min = 0.0, float max = 1.0 ]],
float diffuse_lobe_weight = 0.85 [[ string label = "Diffuse Lobe Weight" ]],
bool use_late_wood_bump = true [[ string widget = "checkBox", int connectable = 0 ]],
float late_wood_bump_depth = 0.002 [[ int connectable = 0, float min = 0.0, float max = 1.0 ]],
bool use_groove_roughness = true [[ string widget = "checkBox", int connectable = 0 ]],
float groove_roughness = 0.19 [[ string label = "Groove Roughness" ]],
// Wood Distortion Noise Params. The actual noise profiles are hidden from the user and only come from the presets,
// just like the C++ Advanced Wood
bool use_fiber_perlin = true [[ string widget = "checkBox", int connectable = 0 ]],
int fiber_perlin_band_count = 3 [[ int connectable = 0, string widget="null" ]],
float4 fiber_perlin_frequencies = {0.025, 0.05, 0.286, 0.0 } [[ int connectable = 0, string widget="null" ]],
float4 fiber_perlin_weights = {3.0, 1.0, 0.2, 0.0 } [[ int connectable = 0, string widget="null" ]],
float fiber_perlin_scale_z = 0.3 [[ int connectable = 0, float min = 0.05, float max = 1.0 ]],
bool use_fiber_cosine = true [[ string widget = "checkBox", int connectable = 0 ]],
int fiber_cosine_band_count = 2 [[ int connectable = 0, string widget="null" ]],
float4 fiber_cosine_frequencies = {0.067, 0.25, 0.0, 0.0} [[ int connectable = 0, string widget="null" ]],
float4 fiber_cosine_weights = {2.5, 0.5, 0.0, 0.0} [[ int connectable = 0, string widget="null" ]],
// Wood Color Noise Params
bool use_growth_perlin = true[[ string widget = "checkBox", int connectable = 0 ]],
int growth_perlin_band_count = 3 [[ int connectable = 0, string widget="null" ]],
float4 growth_perlin_frequencies = {1.0, 0.2, 0.077, 0.0} [[ int connectable = 0, string widget="null" ]],
float4 growth_perlin_weights = {1.0, 2.0, 1.0, 0.0} [[ int connectable = 0, string widget="null" ]],
bool use_diffuse_perlin = true [[ string widget = "checkBox", int connectable = 0 ]],
int diffuse_perlin_band_count = 3 [[ int connectable = 0, string widget="null" ]],
float4 diffuse_perlin_frequencies = {50.0, 10.0, 0.33, 0.0} [[ int connectable = 0, string widget="null" ]],
float4 diffuse_perlin_weights = {0.25, 0.2, 0.05, 0.0} [[ int connectable = 0, string widget="null" ]],
float diffuse_perlin_scale_z = 0.15 [[ int connectable = 0, float min = 0.01, float max = 1.0 ]],
bool use_early_wood_color_perlin = true [[ string widget = "checkBox", int connectable = 0 ]],
int earlycolor_perlin_band_count = 2 [[ int connectable = 0, string widget="null" ]],
float4 earlycolor_perlin_frequencies = {0.123, 0.333, 0.0, 0.0} [[ int connectable = 0, string widget="null" ]],
float4 earlycolor_perlin_weights = {0.3, 0.5, 0.0, 0.0} [[ int connectable = 0, string widget="null" ]],
bool use_late_wood_color_perlin = true [[ string widget = "checkBox", int connectable = 0 ]],
int latecolor_perlin_band_count = 1 [[ int connectable = 0, string widget="null" ]],
float4 latecolor_perlin_frequencies = {0.222, 0.0, 0.0, 0.0} [[ int connectable = 0, string widget="null" ]],
float4 latecolor_perlin_weights = {0.75, 0.0, 0.0, 0.0} [[ int connectable = 0, string widget="null" ]],
// This parameter should not be set by the user and is just used as information to the shader about scene
// units, since it's defined in worldunits and should equal 1 cm.
float cm_scale = 0.01 [[ int worldunits = 1, int connectable=0, string widget="null" ]],
output color Col = 1 [[ string label = "Diffuse Color" ]],
output float Roughness = 0.2,
output float Bump = 0.0
)
{
// Needs to be limited for numerical stability
int adjustedSeed = Seed & 0xfff;
// NOTE: This is not the pixel-identical noise to the C++ implementation, it WILL be slightly different
float woodnoise1(float x)
{
return noise("perlin", x)/2.0;
}
float woodnoise1(vector x)
{
return noise("perlin", x)/2.0;
}
// Evaluate a 1D -> 1D wood noise profile
// The profile is treated as set of pairs (weight, wavelength), each representing a single band of
// Perlin noise. All the bands are evaluated as "weight * noise(frequency * x)" and summed.
float woodNoise1(float4 profile_frequencies, float4 profile_weights, int band_count, float x)
{
float offset = 0.0;
if (band_count > 0) {
float frequency = profile_frequencies.x;
float weight = profile_weights.x;
offset += weight * woodnoise1(frequency * x);
}
if (band_count > 1) {
float frequency = profile_frequencies.y;
float weight = profile_weights.y;
offset += weight * woodnoise1(frequency * x);
}
if (band_count > 2) {
float frequency = profile_frequencies.z;
float weight = profile_weights.z;
offset += weight * woodnoise1(frequency * x);
}
if (band_count > 3) {
float frequency = profile_frequencies.w;
float weight = profile_weights.w;
offset += weight * woodnoise1(frequency * x);
}
return offset;
}
// Evaluate a 3D -> 1D wood noise profile.
// The profile is treated as set of pairs (weight, wavelength), each representing a single band of
// Perlin noise. All the bands are evaluated as "weight * noise(frequency * x)" and summed.
float woodNoise1(float4 profile_frequencies, float4 profile_weights, int band_count, vector p)
{
float offset = 0.0;
if (band_count > 0) {
float frequency = profile_frequencies.x;
float weight = profile_weights.x;
offset += weight * woodnoise1(frequency * p);
}
if (band_count > 1) {
float frequency = profile_frequencies.y;
float weight = profile_weights.y;
offset += weight * woodnoise1(frequency * p);
}
if (band_count > 2) {
float frequency = profile_frequencies.z;
float weight = profile_weights.z;
offset += weight * woodnoise1(frequency * p);
}
if (band_count > 3) {
float frequency = profile_frequencies.w;
float weight = profile_weights.w;
offset += weight * woodnoise1(frequency * p);
}
return offset;
}
// Evaluate a cosine noise profile
vector cosineNoiseRadialDir(float4 profile_frequencies, float4 profile_weights, int band_count,
vector p)
{
float radius = length(vector(p[0],p[1],0.0));
if ( radius < 0.00001 ) {
return p;
}
float cos_theta = p[0] / radius;
float sin_theta = p[1] / radius;
float radius_shift = 0.0;
float angdist = p[2] / TWO_PI;
if (band_count > 0) {
float frequency = profile_frequencies.x;
float weight = profile_weights.x;
radius_shift += weight * cos(frequency * angdist);
}
if (band_count > 1) {
float frequency = profile_frequencies.y;
float weight = profile_weights.y;
radius_shift += weight * cos(frequency * angdist);
}
if (band_count > 2) {
float frequency = profile_frequencies.z;
float weight = profile_weights.z;
radius_shift += weight * cos(frequency * angdist);
}
if (band_count > 3) {
float frequency = profile_frequencies.w;
float weight = profile_weights.w;
radius_shift += weight * cos(frequency * angdist);
}
// Radius at which the distortion reaches full power.
float min_radius = 1.5;
float shift_weight = partialSmoothstep(0.0, min_radius, radius) * radius_shift;
vector p2 = p;
p2[0] += cos_theta * shift_weight;
p2[1] += sin_theta * shift_weight;
return p2;
}
// Wyvill kernel
float wyvill(float r)
{
float tmp = 1.0 - r*r;
return r >= 1.0 ? 0.0 : tmp * tmp * tmp;
}
// Wyvill kernel with pre-squared input.
float wyvillsq(float rsq)
{
float tmp = 1.0 - rsq;
return rsq >= 1.0 ? 0.0 : tmp * tmp * tmp;
}
// The weight ratio of earlywood to latewood. 1.0 indicates all earlywood (lighter). 0.0
// indicates latewood (darker). Computes the radial position as a side-effect.
float computeEarlywoodRatio(vector position, output float radius)
{
// Seed is applied to radius
radius = length(vector(position[0],position[1],0.0)) + abs(adjustedSeed) * 20;
// Growth rate variation
if (use_growth_perlin) {
radius += woodNoise1(growth_perlin_frequencies, growth_perlin_weights,
growth_perlin_band_count, radius);
if (radius < 0.0) {
radius = 0.0;
}
}
// ring_thickness will never be 0, this is worked around in PrismWood rtsi class.
float fraction = frac(radius/ring_thickness);
// As fraction goes from 0 to 1 the wood coloration sectors are
// Earlywood -> Fall -> Latewood -> Rise
// We find the transition points and handle each interval separately.
float fall_to_late_wood = 1.0 - late_wood_ratio;
float early_wood_to_fall = fall_to_late_wood * early_wood_sharpness;
float late_wood_to_rise = fall_to_late_wood + late_wood_ratio * late_wood_sharpness;
// Earlywood
if (fraction <= early_wood_to_fall) {
return 1.0;
}
// Fall
if (fraction <= fall_to_late_wood) {
float fall_width = fall_to_late_wood - early_wood_to_fall;
float t = 1.0 - (fraction - early_wood_to_fall) / fall_width;
return t;
}
// Latewood
if (fraction <= late_wood_to_rise) {
return 0.0;
}
// Rise
float rise_width = 1.0 - late_wood_to_rise;
float t = (fraction - late_wood_to_rise) / rise_width;
return t;
}
// The total wyvill impulse from the radial fibers (rays) at position P.
float weight3DRayImpulses(vector pin)
{
// The segment is the longitudinal subdivision. As rays can have a significant longitudinal
// extent we sum the effect of the ray in both the segment P is in (id_0) and the nearest other
// segment (id_1)
vector p = pin;
p[2] /= ray_ellipse_depth;
int segment_id_0 = int(floor(p[2] / ray_seg_length_z));
float factor = p[2] / ray_seg_length_z - float(segment_id_0);
int segment_id_1 = factor > 0.5 ? segment_id_0 + 1 : segment_id_0 - 1;
int segments[2] = { segment_id_0, segment_id_1 };
// The slice is the circumferential subidivison. Rays have very little circumferential extent so
// we simplify and only use the current slice. This will cause some clipping for rays near the
// edge of a slice.
float theta = atan2(p[1], p[0]);
int slice_id = int(floor((theta + PI) / TWO_PI * float(ray_num_slices)));
if (slice_id == ray_num_slices) {
slice_id--;
}
// Sum the impulses for the two segments affecting P.
float weight = 0.0;
for (int i = 0; i < 2; i++) {
int current_segment = segments[i];
vector hash = noise("hash", slice_id + adjustedSeed * 39, current_segment);
// Each ray starts at a position randomly offset from the center of the tree, at most 5 cm.
float base_radial_offset = 5.0;
if (length(vector(p[0],p[1],0.0)) >= base_radial_offset * hash[0]) {
// The direction of the ray
float ray_theta = (float(slice_id) + hash[0]) / float(ray_num_slices) * TWO_PI - PI;
float ray_pos_z = (float(current_segment) + hash[1]) * ray_seg_length_z;
vector ray_direction = vector(cos(ray_theta), sin(ray_theta), 0.0);
// Scale down the Z component so the ray cross-section is circular.
vector p_normalized = p;
p_normalized[2] = (p_normalized[2] - ray_pos_z) / ray_ellipse_z2x;
// Compute the point to line distance and use it for the wyvill impulse.
float dist = length(cross(ray_direction, p_normalized)) / length(ray_direction);
weight += wyvill(dist / ray_ellipse_scale_x);
}
}
return weight;
}
// The total wyvil impulse of the longitudinal pores at position P.
float weight2DNeighborImpulses(vector p, float wood_weight)
{
if (wood_weight <= 0.0) {
return 0.0;
}
float pore_radius = pore_radius * wood_weight;
// Determine the boundaries of the pore cells that may affect us, given the pore radius and
// cell dimensions.
float x_left = floor((p[0] - pore_radius) / pore_cell_dim);
float x_right = floor((p[0] + pore_radius) / pore_cell_dim);
float y_left = floor((p[1] - pore_radius) / pore_cell_dim);
float y_right = floor((p[1] + pore_radius) / pore_cell_dim);
// Sum the wyvill impulse from all potentially contributing cells.
float weight = 0.0;
float inverse_radius_sq = 1.0 / (pore_radius * pore_radius);
for (int j = int(y_left); j <= int(y_right); j++) {
for (int i = int(x_left); i <= int(x_right); i++) {
// Determine where the pore is in the cell
vector offset = noise("cell", i + adjustedSeed * 37, j);
offset[2] = 0.0;
vector pore_position = (offset + vector(float(i), float(j), 0.0)) * pore_cell_dim;
// Compute the distance to the pore and use it for the wyvill impulse.
vector diff = pore_position - vector(p[0],p[1],0.0);
float diff_sq = dot(diff, diff);
weight += wyvillsq(diff_sq * inverse_radius_sq);
}
}
return weight;
}
// Darken a color based on whether or not that color is on a pore.
color darkenColorWithPores(vector position, color col, float wood_weight,
float pore_color_power,
float pore_radius,
float pore_cell_dim )
{
float pores_weight = weight2DNeighborImpulses(position, wood_weight);
float exponent = (pore_color_power - 1.0) * pores_weight + 1.0;
return pow(col, exponent);
}
// Darken a color based on whether or not that color is on a ray.
color darkenColorWithRays(vector position, color col, output float weight)
{
weight = weight3DRayImpulses(position);
float exponent = (ray_color_power - 1.0) * weight + 1.0;
return pow(col, exponent);
}
// Compute the diffuse color.
color computeDiffuseColor(vector position, float early_wood_ratio, float radius, output float rayweight)
{
// Earlywood color
color early_color = early_wood_color;
if (use_early_wood_color_perlin) {
float exponent = 1.0 + woodNoise1(earlycolor_perlin_frequencies, earlycolor_perlin_weights, earlycolor_perlin_band_count, radius);
early_color = pow(early_color, exponent);
}
// Latewood color
color late_wood_color = pow(early_color, late_wood_color_power);
if (use_manual_late_wood_color) {
late_wood_color = manual_late_wood_color;
}
if (use_late_wood_color_perlin) {
float exponent = 1.0 + woodNoise1(latecolor_perlin_frequencies, latecolor_perlin_weights, latecolor_perlin_band_count, radius);
late_wood_color = pow(late_wood_color, exponent);
}
// Overall diffuse albedo
color diffuse_albedo =
early_wood_ratio * early_color + (1.0 - early_wood_ratio) * late_wood_color;
if (use_diffuse_perlin) {
vector diffuse_position = position;
diffuse_position[2] = diffuse_position[2] * diffuse_perlin_scale_z;
float exponent = 1.0 + woodNoise1(diffuse_perlin_frequencies, diffuse_perlin_weights, diffuse_perlin_band_count, diffuse_position);
diffuse_albedo = pow(diffuse_albedo, exponent);
}
// Darkening from pores
if (use_pores) {
if (pore_type == WOOD_PORE_EARLY) {
diffuse_albedo = darkenColorWithPores(position, diffuse_albedo, early_wood_ratio,
pore_color_power,
pore_radius,
pore_cell_dim);
}
else if (pore_type == WOOD_PORE_LATE) {
diffuse_albedo = darkenColorWithPores(position, diffuse_albedo, 1.0 - early_wood_ratio,
pore_color_power,
pore_radius,
pore_cell_dim);
}
else {
diffuse_albedo = darkenColorWithPores(position, diffuse_albedo, 1.0,
pore_color_power,
pore_radius,
pore_cell_dim);
}
}
// Darkening from rays
if (use_rays) {
diffuse_albedo = darkenColorWithRays(position, diffuse_albedo, rayweight);
}
return diffuse_albedo;
}
// Apply radial cosine distortion to P.
vector distort3DCosineRadialDir(vector p)
{
return cosineNoiseRadialDir(fiber_cosine_frequencies, fiber_cosine_weights,
fiber_cosine_band_count, p);
}
// Apply Perlin distortion to P.
vector distort3DPerlin(vector pp)
{
vector p = pp;
vector p_aniso = p;
p_aniso[2] *= fiber_perlin_scale_z;
float radial_shift = woodNoise1(fiber_perlin_frequencies, fiber_perlin_weights,
fiber_perlin_band_count, p_aniso);
p[0] += radial_shift;
p[1] += radial_shift;
return p;
}
// Apply distortion to P.
vector distort(vector pi)
{
vector p = pi;
// Cosine distortion
if (use_fiber_cosine) {
p = distort3DCosineRadialDir(p);
}
// Perlin distortion
if (use_fiber_perlin) {
p = distort3DPerlin(p);
}
return p;
}
// Compute the height differential from pores
float heightFrom2DNeighborPores(vector position, float wood_weight)
{
// Assume pores are always negative depth
return -weight2DNeighborImpulses(position, wood_weight) * pore_depth;
}
// Compute the total bump displacement
float heightVarForBump(vector position)
{
float height = 0.0;
// compute the weight from the early wood ratio
float radius;
float early_wood_ratio = computeEarlywoodRatio(position, radius);
// consider pores case
if (use_pores) {
if (pore_type == WOOD_PORE_EARLY) {
height += heightFrom2DNeighborPores(position, early_wood_ratio);
}
else if (pore_type == WOOD_PORE_LATE) {
height += heightFrom2DNeighborPores(position, 1.0 - early_wood_ratio);
}
else {
height += heightFrom2DNeighborPores(position, 1.0);
}
}
if (use_late_wood_bump) {
height += (1.0 - early_wood_ratio) * late_wood_bump_depth;
}
return height;
}
// Compute treespace coordinates, pick the right axis
vector tree_position = UVW;
if (axis == 0) // Adjust for X axis
{
tree_position[0] = UVW[1];
tree_position[1] = UVW[2];
tree_position[2] = UVW[0];
}
else if (axis == 1) // Adjust for Y axis
{
tree_position[0] = UVW[2];
tree_position[1] = UVW[0];
tree_position[2] = UVW[1];
}
// Apply the scale
if (scale != 0.0)
{
float scaling = scale;
if (unit_dependent)
{
// Scale by the unit-dependent parameter. This should not be set by the user
// and always be kept at whatever value matches 1 centimeter in the current
// scene units
scaling *= cm_scale;
}
tree_position /= scaling;
}
// Apply random seed simply as a Z shift, simplifies all the noise
// calls and is just as "random". Seed still applies to the cellnoise
// functions that are not position driven.
tree_position[2] += adjustedSeed * 50;
vector tree_distorted_position = distort(tree_position);
Bump = heightVarForBump(tree_distorted_position);
float surface_roughness = roughness;
// Wood lobe
float radius;
float early_wood_ratio = computeEarlywoodRatio(tree_distorted_position, radius);
// Compute the surface roughness
if (use_groove_roughness) {
surface_roughness =
early_wood_ratio * groove_roughness + (1.0 - early_wood_ratio) * surface_roughness;
}
float lobe_roughness = surface_roughness;
// Wood diffuse lobe.
float rayweight = 0.0;
vector wood_f0 = vector(0.04);
vector diffuse_color =
computeDiffuseColor(tree_distorted_position, early_wood_ratio, radius, rayweight) * diffuse_lobe_weight;
// Output
Col = diffuse_color;
Roughness = clamp(lobe_roughness + ray_roughness * rayweight, 0.0, 1.0);
Bump -= rayweight * ray_bump_depth;
}
Octane resources
OCTANE POSTS (URLs have changed, which will break some links but all content remains available).
OCTANE POSTS (URLs have changed, which will break some links but all content remains available).