diff options
Diffstat (limited to 'source/blender/gpu/shaders/gpu_shader_material.glsl')
-rw-r--r-- | source/blender/gpu/shaders/gpu_shader_material.glsl | 205 |
1 files changed, 195 insertions, 10 deletions
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index 0f3ffa8244b..f14db57a26a 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -403,7 +403,7 @@ void math_modulo(float val1, float val2, out float outval) /* change sign to match C convention, mod in GLSL will take absolute for negative numbers, * see https://www.opengl.org/sdk/docs/man/html/mod.xhtml */ - outval = (val1 > 0.0) ? outval : -outval; + outval = (val1 > 0.0) ? outval : outval - val2; } void math_abs(float val1, out float outval) @@ -2378,11 +2378,19 @@ void shade_alpha_obcolor(vec4 col, vec4 obcol, out vec4 outcol) /*********** 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 * the refracted direction */ - float c = abs(dot(Incoming, Normal)); + float c = abs(cosi); float g = eta * eta - 1.0 + c * c; float result; @@ -2399,6 +2407,13 @@ float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) 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) { return sqrt(x * x + y * y); @@ -2492,6 +2507,57 @@ float floorfrac(float x, out int 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 ***************/ #define NUM_LIGHTS 3 @@ -2553,6 +2619,125 @@ void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out vec4 resu node_bsdf_diffuse(color, 0.0, N, result); } +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 clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, out vec4 result) +{ + /* ambient light */ + // TODO: set ambient light to an appropriate value + vec3 L = mix(0.1, 0.03, metallic) * mix(base_color.rgb, subsurface_color.rgb, subsurface * (1.0 - metallic)); + + float eta = (2.0 / (1.0 - sqrt(0.08 * specular))) - 1.0; + + /* set the viewing vector */ + vec3 V = (gl_ProjectionMatrix[3][3] == 0.0) ? -normalize(I) : vec3(0.0, 0.0, 1.0); + + /* get the tangent */ + vec3 Tangent = T; + if (T == vec3(0.0)) { + // if no tangent is set, use a default tangent + if(N.x != N.y || N.x != N.z) { + Tangent = vec3(N.z-N.y, N.x-N.z, N.y-N.x); // (1,1,1) x N + } + else { + Tangent = vec3(N.z-N.y, N.x+N.z, -N.y-N.x); // (-1,1,1) x N + } + } + + /* 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(light_position_world); + + vec3 H = normalize(light_position + V); + + vec3 light_diffuse = gl_LightSource[i].diffuse.rgb; + 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; + + vec3 diffuse_bsdf = (mix(Fd * base_color.rgb, ss * subsurface_color.rgb, subsurface) + Fsheen) * light_diffuse; + vec3 specular_bsdf = Gs * Fs * Ds * light_specular; + diffuse_and_specular_bsdf = diffuse_bsdf * (1.0 - metallic) + specular_bsdf; + } + 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, sqr(clearcoat_roughness)); + 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) * light_specular; + } + clearcoat_bsdf *= max(CNdotL, 0.0); + + L += diffuse_and_specular_bsdf + clearcoat_bsdf; + } + + result = vec4(L, 1.0); +} + void node_bsdf_translucent(vec4 color, vec3 N, out vec4 result) { node_bsdf_diffuse(color, 0.0, N, result); @@ -2846,10 +3031,10 @@ vec2 calc_brick_texture(vec3 p, float mortar_size, float mortar_smooth, float bi float tint = clamp((integer_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias), 0.0, 1.0); float min_dist = min(min(x, y), min(brick_width - x, row_height - y)); - if(min_dist >= mortar_size) { + if (min_dist >= mortar_size) { return vec2(tint, 0.0); } - else if(mortar_smooth == 0.0) { + else if (mortar_smooth == 0.0) { return vec2(tint, 1.0); } else { @@ -3563,12 +3748,12 @@ void node_light_falloff(float strength, float tsmooth, out float quadratic, out constant = strength; } -void node_object_info(out vec3 location, out float object_index, out float material_index, out float random) +void node_object_info(mat4 obmat, vec3 info, out vec3 location, out float object_index, out float material_index, out float random) { - location = vec3(0.0); - object_index = 0.0; - material_index = 0.0; - random = 0.0; + location = obmat[3].xyz; + object_index = info.x; + material_index = info.y; + random = info.z; } void node_normal_map(vec4 tangent, vec3 normal, vec3 texnormal, out vec3 outnormal) |