Fixed the broken GLSL shader and implemented the Disney BRDF in the
real-time view port.
This commit is contained in:
@@ -2378,11 +2378,19 @@ void shade_alpha_obcolor(vec4 col, vec4 obcol, out vec4 outcol)
|
|||||||
|
|
||||||
/*********** NEW SHADER UTILITIES **************/
|
/*********** NEW SHADER UTILITIES **************/
|
||||||
|
|
||||||
float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta)
|
float fresnel_dielectric_0(float eta)
|
||||||
|
{
|
||||||
|
/* compute fresnel reflactance at normal incidence => cosi = 1.0 */
|
||||||
|
float A = (eta - 1.0) / (eta + 1.0);
|
||||||
|
|
||||||
|
return A * A;
|
||||||
|
}
|
||||||
|
|
||||||
|
float fresnel_dielectric_cos(float cosi, float eta)
|
||||||
{
|
{
|
||||||
/* compute fresnel reflectance without explicitly computing
|
/* compute fresnel reflectance without explicitly computing
|
||||||
* the refracted direction */
|
* the refracted direction */
|
||||||
float c = abs(dot(Incoming, Normal));
|
float c = abs(cosi);
|
||||||
float g = eta * eta - 1.0 + c * c;
|
float g = eta * eta - 1.0 + c * c;
|
||||||
float result;
|
float result;
|
||||||
|
|
||||||
@@ -2399,6 +2407,13 @@ float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta)
|
||||||
|
{
|
||||||
|
/* compute fresnel reflectance without explicitly computing
|
||||||
|
* the refracted direction */
|
||||||
|
return fresnel_dielectric_cos(dot(Incoming, Normal), eta);
|
||||||
|
}
|
||||||
|
|
||||||
float hypot(float x, float y)
|
float hypot(float x, float y)
|
||||||
{
|
{
|
||||||
return sqrt(x * x + y * y);
|
return sqrt(x * x + y * y);
|
||||||
@@ -2492,6 +2507,57 @@ float floorfrac(float x, out int i)
|
|||||||
return x - i;
|
return x - i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Principled BSDF operations */
|
||||||
|
|
||||||
|
float sqr(float a)
|
||||||
|
{
|
||||||
|
return a*a;
|
||||||
|
}
|
||||||
|
|
||||||
|
float schlick_fresnel(float u)
|
||||||
|
{
|
||||||
|
float m = clamp(1.0 - u, 0.0, 1.0);
|
||||||
|
float m2 = m * m;
|
||||||
|
return m2 * m2 * m; // pow(m,5)
|
||||||
|
}
|
||||||
|
|
||||||
|
float GTR1(float NdotH, float a)
|
||||||
|
{
|
||||||
|
if (a >= 1.0) return M_1_PI;
|
||||||
|
float a2 = a*a;
|
||||||
|
float t = 1.0 + (a2 - 1.0) * NdotH*NdotH;
|
||||||
|
return (a2 - 1.0) / (M_PI * log(a2) * t);
|
||||||
|
}
|
||||||
|
|
||||||
|
float GTR2(float NdotH, float a)
|
||||||
|
{
|
||||||
|
float a2 = a*a;
|
||||||
|
float t = 1.0 + (a2 - 1.0) * NdotH*NdotH;
|
||||||
|
return a2 / (M_PI * t*t);
|
||||||
|
}
|
||||||
|
|
||||||
|
float GTR2_aniso(float NdotH, float HdotX, float HdotY, float ax, float ay)
|
||||||
|
{
|
||||||
|
return 1.0 / (M_PI * ax*ay * sqr(sqr(HdotX / ax) + sqr(HdotY / ay) + NdotH*NdotH));
|
||||||
|
}
|
||||||
|
|
||||||
|
float smithG_GGX(float NdotV, float alphaG)
|
||||||
|
{
|
||||||
|
float a = alphaG*alphaG;
|
||||||
|
float b = NdotV*NdotV;
|
||||||
|
return 1.0 / (NdotV + sqrt(a + b - a * b));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 rotate_vector(vec3 p, vec3 n, float theta) {
|
||||||
|
return (
|
||||||
|
p * cos(theta) + cross(n, p) *
|
||||||
|
sin(theta) + n * dot(p, n) *
|
||||||
|
(1.0 - cos(theta))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*********** NEW SHADER NODES ***************/
|
/*********** NEW SHADER NODES ***************/
|
||||||
|
|
||||||
#define NUM_LIGHTS 3
|
#define NUM_LIGHTS 3
|
||||||
@@ -2555,9 +2621,122 @@ void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out vec4 resu
|
|||||||
|
|
||||||
void node_bsdf_principled(vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular,
|
void node_bsdf_principled(vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular,
|
||||||
float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat,
|
float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat,
|
||||||
float clearcoat_gloss, float ior, float transparency, float refraction_roughness, vec3 N, vec3 CN, vec3 T, out vec4 result)
|
float clearcoat_gloss, float ior, float transparency, float refraction_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, out vec4 result)
|
||||||
{
|
{
|
||||||
node_bsdf_diffuse(base_color, roughness, N, result);
|
/* ambient light */
|
||||||
|
// TODO: set ambient light to an appropriate value
|
||||||
|
vec3 L = vec3(mix(0.1, 0.03, metallic)) * base_color.rgb;
|
||||||
|
|
||||||
|
float eta = (2.0 / (1.0 - sqrt(0.08 * specular))) - 1.0;
|
||||||
|
|
||||||
|
/* set the viewing vector */
|
||||||
|
vec3 V = -normalize(I);
|
||||||
|
|
||||||
|
/* get the tangent */
|
||||||
|
vec3 Tangent = T;
|
||||||
|
if (T == vec3(0.0)) {
|
||||||
|
// if no tangent is set, use a default tangent
|
||||||
|
Tangent = vec3(1.0, 0.0, 0.0);
|
||||||
|
if (N.x != 0.0 || N.y != 0.0) {
|
||||||
|
vec3 N_xz = normalize(vec3(N.x, 0.0, N.z));
|
||||||
|
|
||||||
|
vec3 axis = normalize(cross(vec3(0.0, 0.0, 1.0), N_xz));
|
||||||
|
float angle = acos(dot(vec3(0.0, 0.0, 1.0), N_xz));
|
||||||
|
|
||||||
|
Tangent = normalize(rotate_vector(vec3(1.0, 0.0, 0.0), axis, angle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* rotate tangent */
|
||||||
|
if (anisotropic_rotation != 0.0) {
|
||||||
|
Tangent = rotate_vector(Tangent, N, anisotropic_rotation * 2.0 * M_PI);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* calculate the tangent and bitangent */
|
||||||
|
vec3 Y = normalize(cross(N, Tangent));
|
||||||
|
vec3 X = cross(Y, N);
|
||||||
|
|
||||||
|
/* fresnel normalization parameters */
|
||||||
|
float F0 = fresnel_dielectric_0(eta);
|
||||||
|
float F0_norm = 1.0 / (1.0 - F0);
|
||||||
|
|
||||||
|
/* directional lights */
|
||||||
|
for (int i = 0; i < NUM_LIGHTS; i++) {
|
||||||
|
vec3 light_position_world = gl_LightSource[i].position.xyz;
|
||||||
|
vec3 light_position = normalize(gl_NormalMatrix * light_position_world);
|
||||||
|
|
||||||
|
vec3 H = normalize(light_position + V);
|
||||||
|
|
||||||
|
vec3 light_specular = gl_LightSource[i].specular.rgb;
|
||||||
|
|
||||||
|
float NdotL = dot(N, light_position);
|
||||||
|
float NdotV = dot(N, V);
|
||||||
|
float LdotH = dot(light_position, H);
|
||||||
|
|
||||||
|
vec3 diffuse_and_specular_bsdf = vec3(0.0);
|
||||||
|
if (NdotL >= 0.0 && NdotV >= 0.0) {
|
||||||
|
float NdotH = dot(N, H);
|
||||||
|
|
||||||
|
float Cdlum = 0.3 * base_color.r + 0.6 * base_color.g + 0.1 * base_color.b; // luminance approx.
|
||||||
|
|
||||||
|
vec3 Ctint = Cdlum > 0 ? base_color.rgb / Cdlum : vec3(1.0); // normalize lum. to isolate hue+sat
|
||||||
|
vec3 Cspec0 = mix(specular * 0.08 * mix(vec3(1.0), Ctint, specular_tint), base_color.rgb, metallic);
|
||||||
|
vec3 Csheen = mix(vec3(1.0), Ctint, sheen_tint);
|
||||||
|
|
||||||
|
// Diffuse fresnel - go from 1 at normal incidence to .5 at grazing
|
||||||
|
// and mix in diffuse retro-reflection based on roughness
|
||||||
|
|
||||||
|
float FL = schlick_fresnel(NdotL), FV = schlick_fresnel(NdotV);
|
||||||
|
float Fd90 = 0.5 + 2.0 * LdotH*LdotH * roughness;
|
||||||
|
float Fd = mix(1.0, Fd90, FL) * mix(1.0, Fd90, FV);
|
||||||
|
|
||||||
|
// Based on Hanrahan-Krueger brdf approximation of isotropic bssrdf
|
||||||
|
// 1.25 scale is used to (roughly) preserve albedo
|
||||||
|
// Fss90 used to "flatten" retroreflection based on roughness
|
||||||
|
float Fss90 = LdotH*LdotH * roughness;
|
||||||
|
float Fss = mix(1.0, Fss90, FL) * mix(1.0, Fss90, FV);
|
||||||
|
float ss = 1.25 * (Fss * (1.0 / (NdotL + NdotV) - 0.5) + 0.5);
|
||||||
|
|
||||||
|
// specular
|
||||||
|
float aspect = sqrt(1.0 - anisotropic * 0.9);
|
||||||
|
float a = sqr(roughness);
|
||||||
|
float ax = max(0.001, a / aspect);
|
||||||
|
float ay = max(0.001, a * aspect);
|
||||||
|
float Ds = GTR2_aniso(NdotH, dot(H, X), dot(H, Y), ax, ay); //GTR2(NdotH, a);
|
||||||
|
float FH = (fresnel_dielectric_cos(LdotH, eta) - F0) * F0_norm;
|
||||||
|
vec3 Fs = mix(Cspec0, vec3(1.0), FH);
|
||||||
|
float roughg = sqr(roughness * 0.5 + 0.5);
|
||||||
|
float Gs = smithG_GGX(NdotL, roughg) * smithG_GGX(NdotV, roughg);
|
||||||
|
|
||||||
|
// sheen
|
||||||
|
vec3 Fsheen = schlick_fresnel(LdotH) * sheen * Csheen;
|
||||||
|
|
||||||
|
diffuse_and_specular_bsdf = (M_1_PI * mix(Fd, ss, subsurface) * base_color.rgb + Fsheen)
|
||||||
|
* (1.0 - metallic) + Gs * Fs * Ds;
|
||||||
|
}
|
||||||
|
diffuse_and_specular_bsdf *= max(NdotL, 0.0);
|
||||||
|
|
||||||
|
float CNdotL = dot(CN, light_position);
|
||||||
|
float CNdotV = dot(CN, V);
|
||||||
|
|
||||||
|
vec3 clearcoat_bsdf = vec3(0.0);
|
||||||
|
if (CNdotL >= 0.0 && CNdotV >= 0.0 && clearcoat > 0.0) {
|
||||||
|
float CNdotH = dot(CN, H);
|
||||||
|
//float FH = schlick_fresnel(LdotH);
|
||||||
|
|
||||||
|
// clearcoat (ior = 1.5 -> F0 = 0.04)
|
||||||
|
float Dr = GTR1(CNdotH, mix(0.1, 0.001, clearcoat_gloss));
|
||||||
|
float Fr = fresnel_dielectric_cos(LdotH, 1.5); //mix(0.04, 1.0, FH);
|
||||||
|
float Gr = smithG_GGX(CNdotL, 0.25) * smithG_GGX(CNdotV, 0.25);
|
||||||
|
|
||||||
|
clearcoat_bsdf = clearcoat * Gr * Fr * Dr * vec3(0.25);
|
||||||
|
}
|
||||||
|
clearcoat_bsdf *= max(CNdotL, 0.0);
|
||||||
|
|
||||||
|
L += light_specular * (diffuse_and_specular_bsdf + clearcoat_bsdf);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = vec4(L, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void node_bsdf_translucent(vec4 color, vec3 N, out vec4 result)
|
void node_bsdf_translucent(vec4 color, vec3 N, out vec4 result)
|
||||||
|
|||||||
@@ -65,12 +65,19 @@ static void node_shader_init_principled(bNodeTree *UNUSED(ntree), bNode *node)
|
|||||||
|
|
||||||
static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
|
static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
|
||||||
{
|
{
|
||||||
if (!in[16].link)
|
// normal
|
||||||
in[16].link = GPU_builtin(GPU_VIEW_NORMAL);
|
if (!in[17].link)
|
||||||
|
in[17].link = GPU_builtin(GPU_VIEW_NORMAL);
|
||||||
else
|
else
|
||||||
GPU_link(mat, "direction_transform_m4v3", in[16].link, GPU_builtin(GPU_VIEW_MATRIX), &in[16].link);
|
GPU_link(mat, "direction_transform_m4v3", in[17].link, GPU_builtin(GPU_VIEW_MATRIX), &in[17].link);
|
||||||
|
|
||||||
return GPU_stack_link(mat, "node_bsdf_principled", in, out);
|
// clearcoat normal
|
||||||
|
if (!in[18].link)
|
||||||
|
in[18].link = GPU_builtin(GPU_VIEW_NORMAL);
|
||||||
|
else
|
||||||
|
GPU_link(mat, "direction_transform_m4v3", in[18].link, GPU_builtin(GPU_VIEW_MATRIX), &in[18].link);
|
||||||
|
|
||||||
|
return GPU_stack_link(mat, "node_bsdf_principled", in, out, GPU_builtin(GPU_VIEW_POSITION));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void node_shader_update_principled(bNodeTree *UNUSED(ntree), bNode *node)
|
static void node_shader_update_principled(bNodeTree *UNUSED(ntree), bNode *node)
|
||||||
|
|||||||
Reference in New Issue
Block a user