Add support for OSL shader to microfacet hair model

This commit is contained in:
Weizhen Huang 2023-01-16 16:16:58 +01:00
parent e69877c217
commit f0529cfabc
7 changed files with 127 additions and 31 deletions

View File

@ -17,8 +17,6 @@ typedef struct MicrofacetHairExtra {
float TT;
float TRT;
float aspect_ratio;
/* Geometry data. */
float4 geom;
} MicrofacetHairExtra;
@ -41,6 +39,9 @@ typedef struct MicrofacetHairBSDF {
/* Circular/Elliptical */
int cross_section;
/* The ratio of the minor axis to the major axis. */
float aspect_ratio;
/* Extra closure. */
ccl_private MicrofacetHairExtra *extra;
} MicrofacetHairBSDF;
@ -74,8 +75,20 @@ ccl_device int bsdf_microfacet_hair_setup(ccl_private ShaderData *sd,
kernel_assert(isfinite_safe(h));
if (bsdf->cross_section == NODE_MICROFACET_HAIR_ELLIPTIC) {
/* Local frame is independent of the ray direction for elliptical hairs. */
bsdf->extra->geom.w = h;
if (bsdf->aspect_ratio > 1.0f) {
bsdf->aspect_ratio = 1.0f / bsdf->aspect_ratio;
/* Switch major and minor axis. */
const float3 minor_axis = safe_normalize(cross(
sd->dPdu, make_float3(bsdf->extra->geom.x, bsdf->extra->geom.y, bsdf->extra->geom.z)));
const float3 major_axis = safe_normalize(cross(minor_axis, sd->dPdu));
/* Local frame is independent of the ray direction for elliptical hairs. */
bsdf->extra->geom = make_float4(major_axis.x, major_axis.y, major_axis.z, h);
}
else {
bsdf->extra->geom.w = h;
}
}
else {
bsdf->extra->geom = make_float4(X.x, X.y, X.z, h);
@ -802,7 +815,7 @@ ccl_device float3 bsdf_microfacet_hair_eval_r_elliptic(ccl_private const ShaderC
/* get elliptical cross section characteristic */
const float a = 1.0f;
/* TODO: rename this as aspect ratio? e is in [0, 0.85], b is in [0.52, 1]. */
const float b = bsdf->extra->aspect_ratio;
const float b = bsdf->aspect_ratio;
const float e2 = 1.0f - sqr(b / a);
/* this follows blender's convention (unlike the circular case?) */
@ -898,7 +911,7 @@ ccl_device float3 bsdf_microfacet_hair_eval_tt_trt_elliptic(KernelGlobals kg,
return zero_float3();
}
/* this follows blender's convention (unlike the circular case?) */
/* TODO: switch wi and wo? */
const float3 wo = wi_;
const float3 wi = wo_;
@ -923,7 +936,7 @@ ccl_device float3 bsdf_microfacet_hair_eval_tt_trt_elliptic(KernelGlobals kg,
/* get elliptical cross section characteristic */
const float a = 1.0f;
const float b = bsdf->extra->aspect_ratio;
const float b = bsdf->aspect_ratio;
const float e2 = 1.0f - sqr(b / a); /* Squared Eccentricity. */
const float gamma_m_min = to_gamma(phi_m_min, a, b) + 1e-3f;
@ -1094,7 +1107,7 @@ ccl_device Spectrum bsdf_microfacet_hair_eval_elliptic(KernelGlobals kg,
const float3 wo = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z));
/* Treat as transparent material if intersection lies outside of the projected radius. */
const float e2 = 1.0f - sqr(bsdf->extra->aspect_ratio);
const float e2 = 1.0f - sqr(bsdf->aspect_ratio);
const float radius = sqrtf(1.0f - e2 * sqr(sin_phi(wi)));
if (fabsf(bsdf->extra->geom.w) > radius) {
*pdf = 0.0f;
@ -1136,7 +1149,7 @@ ccl_device int bsdf_microfacet_hair_sample_elliptic(const KernelGlobals kg,
/* get elliptical cross section characteristic */
const float a = 1.0f;
const float b = bsdf->extra->aspect_ratio;
const float b = bsdf->aspect_ratio;
const float e2 = 1.0f - sqr(b / a);
/* macronormal */
@ -1345,7 +1358,7 @@ ccl_device Spectrum bsdf_microfacet_hair_eval(KernelGlobals kg,
{
ccl_private MicrofacetHairBSDF *bsdf = (ccl_private MicrofacetHairBSDF *)sc;
if (bsdf->cross_section == NODE_MICROFACET_HAIR_CIRCULAR || bsdf->extra->aspect_ratio == 1.0f) {
if (bsdf->cross_section == NODE_MICROFACET_HAIR_CIRCULAR || bsdf->aspect_ratio == 1.0f) {
return bsdf_microfacet_hair_eval_circular(kg, sd, sc, omega_in, pdf);
}
@ -1365,7 +1378,7 @@ ccl_device int bsdf_microfacet_hair_sample(KernelGlobals kg,
{
ccl_private MicrofacetHairBSDF *bsdf = (ccl_private MicrofacetHairBSDF *)sc;
if (bsdf->cross_section == NODE_MICROFACET_HAIR_CIRCULAR || bsdf->extra->aspect_ratio == 1.0f) {
if (bsdf->cross_section == NODE_MICROFACET_HAIR_CIRCULAR || bsdf->aspect_ratio == 1.0f) {
return bsdf_microfacet_hair_sample_circular(
kg, sc, sd, randu, randv, eval, omega_in, pdf, sampled_roughness, eta);
}

View File

@ -23,6 +23,7 @@
#include "kernel/closure/bsdf_toon.h"
#include "kernel/closure/bsdf_hair.h"
#include "kernel/closure/bsdf_hair_principled.h"
#include "kernel/closure/bsdf_hair_microfacet.h"
#include "kernel/closure/bsdf_principled_diffuse.h"
#include "kernel/closure/bsdf_principled_sheen.h"
#include "kernel/closure/volume.h"
@ -1121,6 +1122,49 @@ ccl_device void osl_closure_principled_hair_setup(KernelGlobals kg,
#endif
}
ccl_device void osl_closure_microfacet_hair_setup(KernelGlobals kg,
ccl_private ShaderData *sd,
uint32_t path_flag,
float3 weight,
ccl_private const MicrofacetHairClosure *closure)
{
#ifdef __HAIR__
if (osl_closure_skip(kg, sd, path_flag, LABEL_GLOSSY)) {
return;
}
ccl_private MicrofacetHairBSDF *bsdf = (ccl_private MicrofacetHairBSDF *)bsdf_alloc(
sd, sizeof(MicrofacetHairBSDF), rgb_to_spectrum(weight));
if (!bsdf) {
return;
}
ccl_private MicrofacetHairExtra *extra = (ccl_private MicrofacetHairExtra *)closure_alloc_extra(
sd, sizeof(MicrofacetHairExtra));
if (!extra) {
return;
}
bsdf->N = ensure_valid_reflection(sd->Ng, sd->I, closure->N);
bsdf->sigma = closure->sigma;
bsdf->roughness = closure->roughness;
bsdf->tilt = closure->tilt;
bsdf->eta = closure->eta;
bsdf->cross_section = closure->cross_section;
bsdf->distribution_type = closure->distribution_type;
bsdf->aspect_ratio = closure->aspect_ratio;
bsdf->extra = extra;
bsdf->extra->R = closure->reflection;
bsdf->extra->TT = closure->transmission;
bsdf->extra->TRT = closure->secondary_reflection;
bsdf->extra->geom = make_float4(
closure->major_axis.x, closure->major_axis.y, closure->major_axis.z, 0.0f);
sd->flag |= bsdf_microfacet_hair_setup(sd, bsdf);
#endif
}
/* Volume */
ccl_device void osl_closure_absorption_setup(KernelGlobals kg,

View File

@ -245,6 +245,21 @@ OSL_CLOSURE_STRUCT_BEGIN(PrincipledHair, principled_hair)
OSL_CLOSURE_STRUCT_MEMBER(PrincipledHair, FLOAT, float, eta, NULL)
OSL_CLOSURE_STRUCT_END(PrincipledHair, principled_hair)
OSL_CLOSURE_STRUCT_BEGIN(MicrofacetHair, microfacet_hair)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetHair, VECTOR, packed_float3, N, NULL)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetHair, VECTOR, packed_float3, sigma, NULL)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetHair, FLOAT, float, roughness, NULL)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetHair, FLOAT, float, tilt, NULL)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetHair, FLOAT, float, eta, NULL)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetHair, INT, int, distribution_type, NULL)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetHair, INT, int, cross_section, NULL)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetHair, FLOAT, float, aspect_ratio, NULL)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetHair, FLOAT, float, reflection, NULL)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetHair, FLOAT, float, transmission, NULL)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetHair, FLOAT, float, secondary_reflection, NULL)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetHair, VECTOR, packed_float3, major_axis, NULL)
OSL_CLOSURE_STRUCT_END(MicrofacetHair, microfacet_hair)
OSL_CLOSURE_STRUCT_BEGIN(VolumeAbsorption, absorption)
OSL_CLOSURE_STRUCT_END(VolumeAbsorption, absorption)

View File

@ -51,6 +51,10 @@ shader node_microfacet_hair_bsdf(color Color = color(0.017513, 0.005763, 0.00205
float IOR = 1.55,
string AttrRandom = "geom:curve_random",
float Random = 0.0,
float AspectRatio = 0.85,
float Reflection = 1.0,
float Transmission = 1.0,
float SecondaryReflection = 1.0,
output closure color BSDF = 0)
{
@ -99,5 +103,26 @@ shader node_microfacet_hair_bsdf(color Color = color(0.017513, 0.005763, 0.00205
sigma = m_sigma_from_concentration(0.0, 0.8054375);
}
BSDF = microfacet_hair(Normal, sigma, roughness, Offset, IOR);
int distribution_type_enum = (distribution_type == "GGX") ? 0 : 1;
int cross_section_enum = 0;
normal major_axis = 0.0;
if (cross_section == "Elliptical") {
cross_section_enum = 1;
major_axis = 1.0;
getattribute("geom:N", major_axis);
}
BSDF = microfacet_hair(Normal,
sigma,
roughness,
Offset,
IOR,
distribution_type_enum,
cross_section_enum,
AspectRatio,
Reflection,
Transmission,
SecondaryReflection,
major_axis);
}

View File

@ -60,8 +60,18 @@ closure color principled_hair(normal N,
float coat,
float alpha,
float eta) BUILTIN;
closure color
microfacet_hair(normal N, color sigma, float roughness, float tilt, float eta) BUILTIN;
closure color microfacet_hair(normal N,
color sigma,
float roughness,
float tilt,
float eta,
int distribution_type,
int cross_section,
float aspect_ratio,
float reflection,
float transmission,
float secondary_reflection,
normal major_axis) BUILTIN;
// Volume
closure color henyey_greenstein(float g) BUILTIN;

View File

@ -1002,27 +1002,16 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
}
if (cross_section == NODE_MICROFACET_HAIR_ELLIPTIC) {
uint aspect_ratio_ofs, temp;
svm_unpack_node_uchar4(data_node5.x, &aspect_ratio_ofs, &temp, &temp, &temp);
float aspect_ratio = stack_load_float_default(stack, aspect_ratio_ofs, data_node5.y);
/* Aspect Ratio */
bsdf->extra->aspect_ratio = (aspect_ratio > 1.0f) ? 1.0f / aspect_ratio : aspect_ratio;
bsdf->aspect_ratio = stack_load_float_default(stack, aspect_ratio_ofs, data_node5.y);
const AttributeDescriptor attr_descr_normal = find_attribute(kg, sd, data_node5.z);
const float3 normal = curve_attribute_float3(kg, sd, attr_descr_normal, NULL, NULL);
const float3 binormal = safe_normalize(cross(sd->dPdu, normal));
const float3 major_axis = curve_attribute_float3(kg, sd, attr_descr_normal, NULL, NULL);
/* Align X axis with the ellipse major axis. */
if (aspect_ratio > 1.0f) {
const float3 normal = safe_normalize(cross(binormal, sd->dPdu));
bsdf->extra->geom = make_float4(normal.x, normal.y, normal.z, 0.0f);
}
else {
bsdf->extra->geom = make_float4(binormal.x, binormal.y, binormal.z, 0.0f);
}
/* Align ellipse major axis with the curve normal direction. */
bsdf->extra->geom = make_float4(major_axis.x, major_axis.y, major_axis.z, 0.0f);
}
sd->flag |= bsdf_microfacet_hair_setup(sd, bsdf);

View File

@ -3653,8 +3653,8 @@ NODE_DEFINE(MicrofacetHairBsdfNode)
/* Hair cross-section type specified as enum. */
static NodeEnum cross_section_enum;
distribution_type_enum.insert("Circular", NODE_MICROFACET_HAIR_CIRCULAR);
distribution_type_enum.insert("Elliptical", NODE_MICROFACET_HAIR_ELLIPTIC);
cross_section_enum.insert("Circular", NODE_MICROFACET_HAIR_CIRCULAR);
cross_section_enum.insert("Elliptical", NODE_MICROFACET_HAIR_ELLIPTIC);
SOCKET_ENUM(cross_section, "Cross Section", cross_section_enum, NODE_MICROFACET_HAIR_CIRCULAR);
/* Initialize sockets to their default values. */