Full BSDF

This commit is contained in:
2026-08-07 02:04:01 -07:00
parent 7aeebf2008
commit fe017dd874
55 changed files with 2306 additions and 1215 deletions

View File

@ -74,8 +74,6 @@ def make(context_id, rpasses):
con['color_attachments'] = [attachment_format, attachment_format]
if '_gbuffer2' in wrd.world_defs:
con['color_attachments'].append(attachment_format)
if '_Anisotropy' in wrd.world_defs:
con['color_attachments'].append('RGBA64')
con_mesh = mat_state.data.add_context(con)
mat_state.con_mesh = con_mesh
@ -156,6 +154,8 @@ def make_base(con_mesh, parse_opacity):
vert.add_out('vec3 wnormal')
make_attrib.write_norpos(con_mesh, vert)
frag.write_attrib('vec3 n = normalize(wnormal);')
if '_ClearCoat' in wrd.world_defs:
frag.write_attrib('vec3 nCoat = vec3(0.0, 0.0, 0.0);')
if mat_state.material.lnx_two_sided:
frag.write('if (!gl_FrontFacing) n *= -1;') # Flip normal when drawing back-face
@ -254,16 +254,13 @@ def make_deferred(con_mesh, rpasses):
frag.write('n.xy = n.z >= 0.0 ? n.xy : octahedronWrap(n.xy);')
is_shadeless = mat_state.emission_type == mat_state.EmissionType.SHADELESS
ext_brdf_defs = ('_ClearCoat', '_Sheen', '_Anisotropy', '_Subsurface', '_Transmission')
ext_brdf_defs = ('_ClearCoat', '_Sheen', '_Anisotropy', '_SSS', '_Transmission')
has_ext_brdf = any(d in wrd.world_defs for d in ext_brdf_defs)
if is_shadeless or '_SSS' in wrd.world_defs or '_Hair' in wrd.world_defs or has_ext_brdf:
if is_shadeless or has_ext_brdf:
frag.write('uint matid = 0;')
if is_shadeless:
frag.write('matid = 1;')
frag.write('basecol = emissionCol;')
if '_SSS' in wrd.world_defs or '_Hair' in wrd.world_defs:
frag.add_uniform('int materialID')
frag.write('if (materialID == 2) matid = 2;')
if has_ext_brdf:
frag.add_uniform('int materialID')
frag.write('if (materialID >= 3) matid = uint(materialID);')
@ -283,6 +280,14 @@ def make_deferred(con_mesh, rpasses):
if mat_state.material.lnx_ignore_irradiance:
frag.write('fragColor[GBUF_IDX_2].b = 1.0;')
if '_Anisotropy' in wrd.world_defs:
frag.write('#ifdef _Anisotropy')
if con_mesh.is_elem('tang'):
frag.write('fragColor[GBUF_IDX_2].a = encodeTangent(TBN[0], normalize(wnormal));')
else:
frag.write('fragColor[GBUF_IDX_2].a = -1.0;')
frag.write('#endif')
# Even if the material doesn't use emission we need to write to the
# emission buffer (if used) to prevent undefined behaviour
frag.write('#ifdef _EmissionShaded')
@ -290,14 +295,21 @@ def make_deferred(con_mesh, rpasses):
frag.write('#endif')
if '_SSRefraction' in wrd.world_defs or '_VoxelRefract' in wrd.world_defs:
frag.write('fragColor[GBUF_IDX_REFRACTION] = vec4(1.0, 0.0, 0.0, 1.0);')
frag.write('fragColor[GBUF_IDX_REFRACTION] = vec4(packIOR(1.0), 0.0, 0.0, 1.0);')
if '_Anisotropy' in wrd.world_defs:
frag.write('#ifdef _Anisotropy')
if con_mesh.is_elem('tang'):
frag.write('fragColor[GBUF_IDX_3] = vec4(normalize(TBN[0]), 0.0);')
else:
frag.write('fragColor[GBUF_IDX_3] = vec4(0.0, 0.0, 0.0, 0.0);')
if '_ClearCoat' in wrd.world_defs:
frag.write('#ifdef _ClearCoat')
frag.write('if (dot(nCoat, nCoat) > 0.0) {')
frag.write(' vec3 nCoatNorm = normalize(nCoat);')
frag.write(' nCoatNorm /= (abs(nCoatNorm.x) + abs(nCoatNorm.y) + abs(nCoatNorm.z));')
frag.write(' nCoatNorm.xy = nCoatNorm.z >= 0.0 ? nCoatNorm.xy : octahedronWrap(nCoatNorm.xy);')
frag.write(' fragColor[GBUF_IDX_COAT_NORMAL] = vec4(nCoatNorm.xy, 0.0, 0.0);')
frag.write('} else {')
frag.write(' vec3 nNorm = normalize(n);')
frag.write(' nNorm /= (abs(nNorm.x) + abs(nNorm.y) + abs(nNorm.z));')
frag.write(' nNorm.xy = nNorm.z >= 0.0 ? nNorm.xy : octahedronWrap(nNorm.xy);')
frag.write(' fragColor[GBUF_IDX_COAT_NORMAL] = vec4(nNorm.xy, 0.0, 0.0);')
frag.write('}')
frag.write('#endif')
return con_mesh
@ -403,6 +415,9 @@ def make_forward_mobile(con_mesh):
frag.add_include('std/shadows.glsl')
frag.add_uniform('vec4 casData[shadowmapCascades * 4 + 4]', '_cascadeData', included=True)
frag.add_uniform('vec3 eye', '_cameraPosition')
if is_shadows_atlas:
frag.add_uniform('vec4 tileBoundsSunArray[maxLights * shadowmapCascades]', '_tileBoundsSunArray', included=True)
frag.write('tileBounds = tileBoundsSunArray[0];')
frag.write(f'svisibility = shadowTestCascade({shadowmap_sun}, eye, wposition + n * shadowsBias * 10, shadowsBias, opacity != 1.0);')
else:
frag.write('if (lightPosition.w > 0.0) {')
@ -582,7 +597,7 @@ def make_forward(con_mesh):
frag.write('fragColor[0] = vec4(direct + indirect, packFloat2(occlusion, specular));')
frag.write('fragColor[1] = vec4(n.xy, roughness, metallic);')
if rpdat.rp_ss_refraction or rpdat.lnx_voxelgi_refract:
frag.write(f'fragColor[2] = vec4(1.0, 0.0, 0.0, 1.0);')
frag.write(f'fragColor[2] = vec4(packIOR(1.0), 0.0, 0.0, 1.0);')
else:
frag.add_out('vec4 fragColor[1]')
@ -683,6 +698,8 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False):
frag.write('vec3 albedo = surfaceAlbedo(basecol, metallic);')
frag.write('vec3 f0 = surfaceF0(basecol, metallic);')
if '_ExtBRDF' in wrd.world_defs:
frag.write('f0 = mix(f0, basecol, specularTint);')
if '_Brdf' in wrd.world_defs:
frag.add_uniform('sampler2D senvmapBrdf', link='$brdf.png')
@ -752,6 +769,18 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False):
frag.write('}')
frag.write('vec3 direct = vec3(0.0);')
if '_ExtBRDF' in wrd.world_defs:
frag.write('#ifdef _ExtBRDF')
if '_Sheen' in wrd.world_defs:
frag.write('brdf_sheenWeight = sheenAttenuation(sheen, sheenRough, sheenTint, dotNV);')
if '_ClearCoat' in wrd.world_defs:
frag.write('brdf_coatWeight = coatAttenuation(clearcoat, coatIOR, nCoat, vVec);')
frag.write('brdf_coatTintAbsorb = coatTintAttenuation(clearcoat, coatTint, nCoat, vVec);')
frag.write('brdf_coatF0 = (coatIOR - 1.0) / (coatIOR + 1.0); brdf_coatF0 = brdf_coatF0 * brdf_coatF0;')
if '_Transmission' in wrd.world_defs:
frag.write('brdf_transmissionF0 = (ior - 1.0) / (ior + 1.0); brdf_transmissionF0 = brdf_transmissionF0 * brdf_transmissionF0;')
frag.write('#endif')
if '_Sun' in wrd.world_defs:
frag.add_uniform('vec3 sunCol', '_sunColor')
frag.add_uniform('vec3 sunDir', '_sunDirection')
@ -771,6 +800,9 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False):
frag.add_include('std/shadows.glsl')
frag.add_uniform('vec4 casData[shadowmapCascades * 4 + 4]', '_cascadeData', included=True)
frag.add_uniform('vec3 eye', '_cameraPosition')
if is_shadows_atlas:
frag.add_uniform('vec4 tileBoundsSunArray[maxLights * shadowmapCascades]', '_tileBoundsSunArray', included=True)
frag.write('tileBounds = tileBoundsSunArray[0];')
frag.write(f'svisibility = shadowTestCascade({shadowmap_sun},')
if is_transparent_shadows:
frag.write(f'{shadowmap_sun_tr},')
@ -804,7 +836,21 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False):
if '_VoxelShadow' in wrd.world_defs:
frag.write('svisibility *= (1.0 - traceShadow(wposition, n, voxels, voxelsSDF, sunDir, clipmaps, gl_FragCoord.xy, velocity).r) * voxelgiShad;')
frag.write('}') # receiveShadow
frag.write('direct += (lambertDiffuseBRDF(albedo, sdotNL) + specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * specular) * sunCol * svisibility;')
if '_ExtBRDF' in wrd.world_defs:
frag.write('float sunLayerWeight;')
frag.write('vec3 sdirect = applyExtBRDFLayers(')
frag.write(' lambertDiffuseBRDF(albedo, sdotNL) + specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * specular,')
frag.write(' albedo, f0, roughness, sdotNL, dotNV, sdotNH, sdotVH, n, sunDir, vVec, sh')
if '_ClearCoat' in wrd.world_defs:
frag.write(', clearcoat, clearcoatRough, coatIOR, coatTint, nCoat')
if '_Sheen' in wrd.world_defs:
frag.write(', sheen, sheenRough, sheenTint')
if '_Transmission' in wrd.world_defs:
frag.write(', transmission, transmissionRough, ior, thinWall')
frag.write(', sunLayerWeight);')
frag.write('direct += sdirect * sunCol * svisibility;')
else:
frag.write('direct += (lambertDiffuseBRDF(albedo, sdotNL) + specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * specular) * sunCol * svisibility;')
# sun
if '_SinglePoint' in wrd.world_defs:
@ -846,13 +892,13 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False):
frag.add_uniform('vec3 eye', '_cameraPosition')
frag.write(', gbufferD, invVP, eye')
if '_ClearCoat' in wrd.world_defs:
frag.write(', clearcoat, clearcoatRough, coatIOR, coatTint')
frag.write(', clearcoat, clearcoatRough, coatIOR, coatTint, nCoat')
if '_Sheen' in wrd.world_defs:
frag.write(', sheen, sheenRough, sheenTint')
if '_Anisotropy' in wrd.world_defs:
frag.write(', anisotropy, anisoRot, tangent')
if '_Subsurface' in wrd.world_defs:
frag.write(', subsurface, subsurfaceColor, subsurfaceRadius, subsurfaceAnisotropy')
if '_SSS' in wrd.world_defs:
frag.write(', subsurface, subsurfaceColor, subsurfaceRadius * subsurfaceScale, subsurfaceAnisotropy')
if '_Transmission' in wrd.world_defs:
frag.write(', transmission, transmissionRough, ior, thinWall')
frag.write(');')
@ -867,7 +913,7 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False):
if '_VoxelRefract' in wrd.world_defs and parse_opacity:
frag.write('if (opacity < 1.0) {')
frag.write(' vec3 refraction = traceRefraction(wposition, n, voxels, voxelsSDF, vVec, ior, roughness * roughness, clipmaps, gl_FragCoord.xy, velocity, opacity).rgb * (1.0 - F) * voxelgiRefr;')
frag.write(' vec3 refraction = traceRefraction(wposition, n, voxels, voxelsSDF, vVec, ior, roughness * roughness, clipmaps, gl_FragCoord.xy, velocity, opacity).rgb * (1.0 - F);')
frag.write(' indirect = mix(refraction, indirect, opacity);')
frag.write(' direct = mix(refraction, direct, opacity);')
frag.write('}')
@ -882,25 +928,27 @@ def _write_material_attribs_default(frag: shader.Shader, parse_opacity: bool):
# by the shader compiler
frag.write('vec3 emissionCol;')
# Extended BRDF parameters
frag.write('float subsurface = 0.0;')
frag.write('vec3 subsurfaceRadius = vec3(0.0);')
frag.write('vec3 subsurfaceColor = vec3(0.8);')
frag.write('vec3 specularTint = vec3(1.0);')
frag.write('float anisotropy = 0.0;')
frag.write('float anisoRot = 0.0;')
frag.write('float sheen = 0.0;')
frag.write('float sheenRough = 0.5;')
frag.write('vec3 sheenTint = vec3(1.0);')
frag.write('float clearcoat = 0.0;')
frag.write('float clearcoatRough = 0.03;')
frag.write('float transmission = 0.0;')
frag.write('float transmissionRough = 0.0;')
frag.write('float thinWall = 0.0;')
frag.write('vec3 tangent = vec3(0.0);')
frag.write('float subsurfaceScale = 0.05;')
frag.write('float subsurfaceAnisotropy = 0.0;')
frag.write('float coatIOR = 1.5;')
frag.write('vec3 coatTint = vec3(1.0);')
frag.write('float subsurface;')
frag.write('vec3 subsurfaceRadius;')
frag.write('vec3 subsurfaceColor;')
frag.write('vec3 specularTint;')
frag.write('float anisotropy;')
frag.write('float anisoRot;')
frag.write('float sheen;')
frag.write('float sheenRough;')
frag.write('vec3 sheenTint;')
frag.write('float clearcoat;')
frag.write('float clearcoatRough;')
frag.write('float transmission;')
frag.write('float transmissionRough;')
frag.write('float thinWall;')
frag.write('vec3 tangent;')
frag.write('float subsurfaceScale;')
frag.write('float subsurfaceAnisotropy;')
frag.write('float coatIOR;')
frag.write('vec3 coatTint;')
frag.write('float ior = 1.45;')
if parse_opacity:
frag.write('float opacity;')
frag.write('float ior = 1.45;')
else:
frag.write('float opacity = 1.0;')