From 40bca62f96e094d04729bc4d6c7e656ea6105ed0 Mon Sep 17 00:00:00 2001 From: Onek8 Date: Mon, 7 Sep 2026 11:12:57 -0700 Subject: [PATCH 1/4] Get Transform Node Replacement Update --- leenkx/Sources/leenkx/logicnode/GetTransformNode.hx | 2 +- .../lnx/logicnode/transform/LN_get_object_transform.py | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/leenkx/Sources/leenkx/logicnode/GetTransformNode.hx b/leenkx/Sources/leenkx/logicnode/GetTransformNode.hx index ad695b7d..6ce44c11 100644 --- a/leenkx/Sources/leenkx/logicnode/GetTransformNode.hx +++ b/leenkx/Sources/leenkx/logicnode/GetTransformNode.hx @@ -10,7 +10,7 @@ class GetTransformNode extends LogicNode { override function get(from: Int): Dynamic { var object: Object = inputs[0].get(); - var relative: Bool = inputs[1].get(); + var relative: Bool = inputs.length > 1 && inputs[1] != null ? inputs[1].get() : false; if (object == null) return null; diff --git a/leenkx/blender/lnx/logicnode/transform/LN_get_object_transform.py b/leenkx/blender/lnx/logicnode/transform/LN_get_object_transform.py index 3870dddb..d9851d2b 100644 --- a/leenkx/blender/lnx/logicnode/transform/LN_get_object_transform.py +++ b/leenkx/blender/lnx/logicnode/transform/LN_get_object_transform.py @@ -17,5 +17,10 @@ class GetTransformNode(LnxLogicTreeNode): def get_replacement_node(self, node_tree: bpy.types.NodeTree): if self.lnx_version not in (0, 1): raise LookupError() - - return NodeReplacement.Identity(self) + + return NodeReplacement( + 'LNGetTransformNode', self.lnx_version, 'LNGetTransformNode', 2, + in_socket_mapping={0: 0}, + out_socket_mapping={0: 0}, + input_defaults={1: False}, + ) From d44fd9993a5fdf043b95cdeb932e3a6ee7a5ca8e Mon Sep 17 00:00:00 2001 From: Onek8 Date: Mon, 7 Sep 2026 11:33:15 -0700 Subject: [PATCH 2/4] Get Transform Update --- leenkx/Sources/leenkx/logicnode/GetTransformNode.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/leenkx/Sources/leenkx/logicnode/GetTransformNode.hx b/leenkx/Sources/leenkx/logicnode/GetTransformNode.hx index 6ce44c11..ad695b7d 100644 --- a/leenkx/Sources/leenkx/logicnode/GetTransformNode.hx +++ b/leenkx/Sources/leenkx/logicnode/GetTransformNode.hx @@ -10,7 +10,7 @@ class GetTransformNode extends LogicNode { override function get(from: Int): Dynamic { var object: Object = inputs[0].get(); - var relative: Bool = inputs.length > 1 && inputs[1] != null ? inputs[1].get() : false; + var relative: Bool = inputs[1].get(); if (object == null) return null; From 42fdff47572405725d5984d66a38bb00975b7bab Mon Sep 17 00:00:00 2001 From: Onek8 Date: Tue, 8 Sep 2026 22:02:48 -0700 Subject: [PATCH 3/4] TriVoxel: Burley + (EON, Gotanda, Chan) Diffuse Models --- .../deferred_light/deferred_light.frag.glsl | 8 +- .../deferred_light.frag.glsl | 8 +- leenkx/Shaders/std/brdf.glsl | 193 ++++++++++++++++++ leenkx/Shaders/std/light.glsl | 6 +- leenkx/Shaders/std/light_mobile.glsl | 8 +- .../voxel_resolve_ao.comp.glsl | 2 +- .../voxel_resolve_diffuse.comp.glsl | 4 +- leenkx/blender/lnx/make_renderpath.py | 13 ++ leenkx/blender/lnx/material/make_mesh.py | 11 +- leenkx/blender/lnx/material/make_voxel.py | 3 +- leenkx/blender/lnx/props_renderpath.py | 8 + leenkx/blender/lnx/props_ui.py | 1 + 12 files changed, 241 insertions(+), 24 deletions(-) diff --git a/leenkx/Shaders/deferred_light/deferred_light.frag.glsl b/leenkx/Shaders/deferred_light/deferred_light.frag.glsl index 6420a4e0..ae4bba58 100644 --- a/leenkx/Shaders/deferred_light/deferred_light.frag.glsl +++ b/leenkx/Shaders/deferred_light/deferred_light.frag.glsl @@ -420,7 +420,7 @@ void main() { #endif #endif - envl.rgb *= albedo; + envl.rgb *= diffuseIBL(albedo, roughness, f0, dotNV); #ifdef _Brdf envl.rgb *= 1.0 - F; //LV: We should take refracted light into account @@ -581,15 +581,15 @@ void main() { vec3 sdirect; if (abs(matp0.x) > 0.001 && dot(wTangent, wTangent) > 0.001) { vec3 sbitangent = normalize(cross(n, wTangent)); - sdirect = lambertDiffuseBRDF(albedo, sdotNL) + + sdirect = diffuseBRDF(albedo, roughness, f0, sdotNL, dotNV, sdotVH) + anisotropicBRDF(f0, roughness, matp0.x, matp0.y, wTangent, sbitangent, n, sunDir, v, sdotNL, dotNV) * occspec.y; } else { - sdirect = lambertDiffuseBRDF(albedo, sdotNL) + + sdirect = diffuseBRDF(albedo, roughness, f0, sdotNL, dotNV, sdotVH) + specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * occspec.y; } #else - vec3 sdirect = lambertDiffuseBRDF(albedo, sdotNL) + + vec3 sdirect = diffuseBRDF(albedo, roughness, f0, sdotNL, dotNV, sdotVH) + specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * occspec.y; #endif diff --git a/leenkx/Shaders/deferred_light_mobile/deferred_light.frag.glsl b/leenkx/Shaders/deferred_light_mobile/deferred_light.frag.glsl index 27e6958b..75512780 100644 --- a/leenkx/Shaders/deferred_light_mobile/deferred_light.frag.glsl +++ b/leenkx/Shaders/deferred_light_mobile/deferred_light.frag.glsl @@ -227,7 +227,7 @@ void main() { #endif #endif - envl.rgb *= albedo; + envl.rgb *= diffuseIBL(albedo, roughness, f0, dotNV); #ifdef _Rad // Indirect specular envl.rgb += prefilteredColor * (f0 * envBRDF.x + envBRDF.y) * 1.5 * occspec.y; @@ -342,15 +342,15 @@ void main() { vec3 sdirect; if (abs(matp0.x) > 0.001 && dot(wTangent, wTangent) > 0.001) { vec3 sbitangent = normalize(cross(n, wTangent)); - sdirect = lambertDiffuseBRDF(albedo, sdotNL) + + sdirect = diffuseBRDF(albedo, roughness, f0, sdotNL, dotNV, sdotVH) + anisotropicBRDF(f0, roughness, matp0.x, matp0.y, wTangent, sbitangent, n, sunDir, v, sdotNL, dotNV) * occspec.y; } else { - sdirect = lambertDiffuseBRDF(albedo, sdotNL) + + sdirect = diffuseBRDF(albedo, roughness, f0, sdotNL, dotNV, sdotVH) + specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * occspec.y; } #else - vec3 sdirect = lambertDiffuseBRDF(albedo, sdotNL) + + vec3 sdirect = diffuseBRDF(albedo, roughness, f0, sdotNL, dotNV, sdotVH) + specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * occspec.y; #endif diff --git a/leenkx/Shaders/std/brdf.glsl b/leenkx/Shaders/std/brdf.glsl index d7c1aa54..74aea827 100644 --- a/leenkx/Shaders/std/brdf.glsl +++ b/leenkx/Shaders/std/brdf.glsl @@ -88,6 +88,199 @@ vec3 lambertDiffuseBRDF(const vec3 albedo, const float nl) { return albedo * INV_PI * nl; } +#ifdef _BurleyDiffuse +vec3 burleyDiffuseBRDF(const vec3 albedo, const float roughness, + const float dotNL, const float dotNV, const float dotVH) { + float nl = clamp(dotNL, 0.0, 1.0); + float nv = clamp(dotNV, 0.0, 1.0); + float energyBias = mix(0.0, 0.5, roughness); + float energyFactor = mix(1.0, 1.0 / 1.51, roughness); + float fd90 = energyBias + 2.0 * roughness * dotVH * dotVH; + float lightScatter = 1.0 + (fd90 - 1.0) * pow(1.0 - nl, 5.0); + float viewScatter = 1.0 + (fd90 - 1.0) * pow(1.0 - nv, 5.0); + return albedo * INV_PI * lightScatter * viewScatter * energyFactor * nl; +} +#endif + +#ifdef _EONDiffuse +const float constant1_FON = 0.5 - 2.0 / (3.0 * PI); +const float constant2_FON = 2.0 / 3.0 - 28.0 / (15.0 * PI); + +float E_FON_approx(float mu, float r) { + float mucomp = 1.0 - mu; + const float g1 = 0.0571085289; + const float g2 = 0.491881867; + const float g3 = -0.332181442; + const float g4 = 0.0714429953; + float GoverPi = mucomp * (g1 + mucomp * (g2 + mucomp * (g3 + mucomp * g4))); + return (1.0 + r * GoverPi) / (1.0 + constant1_FON * r); +} + +vec3 eonDiffuseBRDF(const vec3 albedo, const float roughness, + const float dotNL, const float dotNV, const float dotVH) { + float r = roughness; + float mu_i = clamp(dotNL, 0.0, 1.0); + float mu_o = clamp(dotNV, 0.0, 1.0); + if (mu_i < 1.0e-7 || mu_o < 1.0e-7) return vec3(0.0); + float dotLV = 2.0 * dotVH * dotVH - 1.0; + float s = dotLV - mu_i * mu_o; + float sovertF = s > 0.0 ? s / max(mu_i, mu_o) : s; + float AF = 1.0 / (1.0 + constant1_FON * r); + vec3 f_ss = (albedo * INV_PI) * AF * (1.0 + r * sovertF); + float EFo = E_FON_approx(mu_o, r); + float EFi = E_FON_approx(mu_i, r); + float avgEF = AF * (1.0 + constant2_FON * r); + vec3 rho_ms = (albedo * albedo) * avgEF + / max(vec3(1.0) - albedo * (1.0 - avgEF), vec3(1.0e-7)); + const float eps = 1.0e-7; + vec3 f_ms = (rho_ms * INV_PI) + * max(eps, 1.0 - EFo) + * max(eps, 1.0 - EFi) + / max(eps, 1.0 - avgEF); + return (f_ss + f_ms) * mu_i; +} +#endif + +#ifdef _GotandaDiffuse +vec3 gotandaDiffuseBRDF(const vec3 albedo, const float roughness, const vec3 f0, + const float dotNL, const float dotNV, const float dotVH) { + float nl = clamp(dotNL, 0.0, 1.0); + float nv = clamp(dotNV, 0.0, 1.0); + float a = roughness * roughness; + float a2 = a * a; + float dotLV = 2.0 * dotVH * dotVH - 1.0; + float Cosri = dotLV - nv * nl; + float a2_13 = a2 + 1.36053; + float Fr = (1.0 - (0.542026 * a2 + 0.303573 * a) / a2_13) + * (1.0 - pow(1.0 - nv, 5.0 - 4.0 * a2) / a2_13) + * ((-0.733996 * a2 * a + 1.50912 * a2 - 1.16402 * a) + * pow(1.0 - nv, 1.0 + 1.0 / (39.0 * a2 * a2 + 1.0)) + 1.0); + float Lm = (max(1.0 - 2.0 * a, 0.0) * (1.0 - pow(1.0 - nl, 5.0)) + + min(2.0 * a, 1.0)) * (1.0 - 0.5 * a * (nl - 1.0)) * nl; + float Vd = (a2 / ((a2 + 0.09) * (1.31072 + 0.995584 * nv))) + * (1.0 - pow(1.0 - nl, + (1.0 - 0.3726732 * nv * nv) + / (0.188566 + 0.38841 * nv))); + float Bp = Cosri < 0.0 ? 1.4 * nv * nl * Cosri : Cosri; + vec3 Lr = (21.0 / 20.0) * (1.0 - f0) * (Fr * Lm + Vd + Bp); + return max(albedo * INV_PI * Lr, vec3(0.0)); +} +#endif + +#ifdef _ChanDiffuse +vec3 chanDiffuseBRDF(const vec3 albedo, const float roughness, + const float dotNL, const float dotNV, const float dotVH) { + float nl = clamp(dotNL, 0.0, 1.0); + float nv = clamp(dotNV, 0.0, 1.0); + float vh = clamp(dotVH, 0.0, 1.0); + float a = roughness * roughness; + float a2 = a * a; + float g = clamp((1.0 / 18.0) * log2(2.0 / max(a2, 1e-7) - 1.0), 0.0, 1.0); + float dotNH = clamp((nl + nv) / max(2.0 * vh, 1e-5), 0.0, 1.0); + float F0 = vh + pow(1.0 - vh, 5.0); + float FdV = 1.0 - 0.75 * pow(1.0 - nv, 5.0); + float FdL = 1.0 - 0.75 * pow(1.0 - nl, 5.0); + float Fd = mix(F0, FdV * FdL, clamp(2.2 * g - 0.5, 0.0, 1.0)); + float Fb = ((34.5 * g - 59.0) * g + 24.5) * vh + * exp2(-max(73.2 * g - 21.2, 8.9) * sqrt(dotNH)); + float Lobe = clamp(Fd + Fb, 0.0, 1.0); + return albedo * INV_PI * Lobe * nl; +} +#endif + +vec3 diffuseBRDF(const vec3 albedo, const float roughness, const vec3 f0, + const float dotNL, const float dotNV, const float dotVH) { + #ifdef _BurleyDiffuse + return burleyDiffuseBRDF(albedo, roughness, dotNL, dotNV, dotVH); + #elif defined(_EONDiffuse) + return eonDiffuseBRDF(albedo, roughness, dotNL, dotNV, dotVH); + #elif defined(_GotandaDiffuse) + return gotandaDiffuseBRDF(albedo, roughness, f0, dotNL, dotNV, dotVH); + #elif defined(_ChanDiffuse) + return chanDiffuseBRDF(albedo, roughness, dotNL, dotNV, dotVH); + #else + return lambertDiffuseBRDF(albedo, dotNL); + #endif +} + +vec3 lambertDiffuseIBL(const vec3 albedo) { + return albedo; +} + +#ifdef _BurleyDiffuse +vec3 burleyDiffuseIBL(const vec3 albedo, const float roughness, const float dotNV) { + float nv = clamp(dotNV, 0.0, 1.0); + float energyBias = mix(0.0, 0.5, roughness); + float energyFactor = mix(1.0, 1.0 / 1.51, roughness); + float fd90 = energyBias + 2.0 * roughness * nv * nv; + float viewScatter = 1.0 + (fd90 - 1.0) * pow(1.0 - nv, 5.0); + return albedo * viewScatter * energyFactor; +} +#endif + +#ifdef _EONDiffuse +vec3 eonDiffuseIBL(const vec3 albedo, const float roughness, const float dotNV) { + float r = roughness; + float AF = 1.0 / (1.0 + constant1_FON * r); + float EF = E_FON_approx(clamp(dotNV, 0.0, 1.0), r); + float avgEF = AF * (1.0 + constant2_FON * r); + vec3 rho_ms = (albedo * albedo) * avgEF + / max(vec3(1.0) - albedo * (1.0 - avgEF), vec3(1.0e-7)); + return max(albedo * EF + rho_ms * (1.0 - EF), vec3(0.0)); +} +#endif + +#ifdef _GotandaDiffuse +vec3 gotandaDiffuseIBL(const vec3 albedo, const float roughness, const vec3 f0, const float dotNV) { + float nv = clamp(dotNV, 0.0, 1.0); + float a = roughness * roughness; + float a2 = a * a; + float a2_13 = a2 + 1.36053; + float Fr = (1.0 - (0.542026 * a2 + 0.303573 * a) / a2_13) + * (1.0 - pow(1.0 - nv, 5.0 - 4.0 * a2) / a2_13) + * ((-0.733996 * a2 * a + 1.50912 * a2 - 1.16402 * a) + * pow(1.0 - nv, 1.0 + 1.0 / (39.0 * a2 * a2 + 1.0)) + 1.0); + float Lm = (max(1.0 - 2.0 * a, 0.0) * (1.0 - pow(1.0 - nv, 5.0)) + + min(2.0 * a, 1.0)) * (1.0 - 0.5 * a * (nv - 1.0)) * nv; + float Vd = (a2 / ((a2 + 0.09) * (1.31072 + 0.995584 * nv))) + * (1.0 - pow(1.0 - nv, + (1.0 - 0.3726732 * nv * nv) + / (0.188566 + 0.38841 * nv))); + float Cosri = 1.0 - nv * nv; + float Bp = Cosri; + vec3 Lr = (21.0 / 20.0) * (1.0 - f0) * (Fr * Lm + Vd + Bp); + return max(albedo * Lr, vec3(0.0)); +} +#endif + +#ifdef _ChanDiffuse +vec3 chanDiffuseIBL(const vec3 albedo, const float roughness, const float dotNV) { + float nv = clamp(dotNV, 0.0, 1.0); + float a = roughness * roughness; + float a2 = a * a; + float g = clamp((1.0 / 18.0) * log2(2.0 / max(a2, 1e-7) - 1.0), 0.0, 1.0); + float FdV = 1.0 - 0.75 * pow(1.0 - nv, 5.0); + float Fd = mix(1.0, FdV * FdV, clamp(2.2 * g - 0.5, 0.0, 1.0)); + float Fb = ((34.5 * g - 59.0) * g + 24.5) + * exp2(-max(73.2 * g - 21.2, 8.9) * sqrt(nv)); + return albedo * clamp(Fd + Fb, 0.0, 1.0); +} +#endif + +vec3 diffuseIBL(const vec3 albedo, const float roughness, const vec3 f0, const float dotNV) { + #ifdef _BurleyDiffuse + return burleyDiffuseIBL(albedo, roughness, dotNV); + #elif defined(_EONDiffuse) + return eonDiffuseIBL(albedo, roughness, dotNV); + #elif defined(_GotandaDiffuse) + return gotandaDiffuseIBL(albedo, roughness, f0, dotNV); + #elif defined(_ChanDiffuse) + return chanDiffuseIBL(albedo, roughness, dotNV); + #else + return lambertDiffuseIBL(albedo); + #endif +} + vec3 surfaceAlbedo(const vec3 baseColor, const float metalness) { return mix(baseColor, vec3(0.0), metalness); } diff --git a/leenkx/Shaders/std/light.glsl b/leenkx/Shaders/std/light.glsl index 53b2d4a3..51d872d2 100644 --- a/leenkx/Shaders/std/light.glsl +++ b/leenkx/Shaders/std/light.glsl @@ -131,15 +131,15 @@ vec3 sampleLightCore(const vec3 p, const vec3 n, const vec3 v, const float dotNV #ifdef _Anisotropy if (abs(anisotropy) > 0.001 && dot(tangent, tangent) > 0.001) { vec3 bitangent = normalize(cross(n, tangent)); - standard = lambertDiffuseBRDF(albedo, dotNL) + + standard = diffuseBRDF(albedo, rough, f0, dotNL, dotNV, dotVH) + anisotropicBRDF(f0, rough, anisotropy, anisoRot, tangent, bitangent, n, l, v, dotNL, dotNV) * spec; } else { - standard = lambertDiffuseBRDF(albedo, dotNL) + + standard = diffuseBRDF(albedo, rough, f0, dotNL, dotNV, dotVH) + specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec; } #else - standard = lambertDiffuseBRDF(albedo, dotNL) + + standard = diffuseBRDF(albedo, rough, f0, dotNL, dotNV, dotVH) + specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec; #endif diff --git a/leenkx/Shaders/std/light_mobile.glsl b/leenkx/Shaders/std/light_mobile.glsl index 851c0505..58878fd8 100644 --- a/leenkx/Shaders/std/light_mobile.glsl +++ b/leenkx/Shaders/std/light_mobile.glsl @@ -83,16 +83,16 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co vec3 direct; if (abs(anisotropy) > 0.001 && dot(tangent, tangent) > 0.001) { vec3 bitangent = normalize(cross(n, tangent)); - direct = lambertDiffuseBRDF(albedo, dotNL) + + direct = diffuseBRDF(albedo, rough, f0, dotNL, dotNV, dotVH) + anisotropicBRDF(f0, rough, anisotropy, anisoRot, tangent, bitangent, n, l, v, dotNL, dotNV) * spec; } else { - direct = lambertDiffuseBRDF(albedo, dotNL) + + direct = diffuseBRDF(albedo, rough, f0, dotNL, dotNV, dotVH) + specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec; } #else - vec3 direct = lambertDiffuseBRDF(albedo, dotNL) + - specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec; + vec3 direct = diffuseBRDF(albedo, rough, f0, dotNL, dotNV, dotVH) + + specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec; #endif #ifdef _ExtBRDF diff --git a/leenkx/Shaders/voxel_resolve_ao/voxel_resolve_ao.comp.glsl b/leenkx/Shaders/voxel_resolve_ao/voxel_resolve_ao.comp.glsl index cae825cb..3d7326f2 100644 --- a/leenkx/Shaders/voxel_resolve_ao/voxel_resolve_ao.comp.glsl +++ b/leenkx/Shaders/voxel_resolve_ao/voxel_resolve_ao.comp.glsl @@ -151,7 +151,7 @@ void main() { #endif #endif - envl.rgb *= albedo; + envl.rgb *= diffuseIBL(albedo, roughness, f0, dotNV); #ifdef _Brdf envl.rgb *= 1.0 - F; //LV: We should take refracted light into account diff --git a/leenkx/Shaders/voxel_resolve_diffuse/voxel_resolve_diffuse.comp.glsl b/leenkx/Shaders/voxel_resolve_diffuse/voxel_resolve_diffuse.comp.glsl index 76121726..4d4e6c2d 100644 --- a/leenkx/Shaders/voxel_resolve_diffuse/voxel_resolve_diffuse.comp.glsl +++ b/leenkx/Shaders/voxel_resolve_diffuse/voxel_resolve_diffuse.comp.glsl @@ -137,7 +137,7 @@ void main() { envl.rgb = pow(envl.rgb, vec3(2.2)); #endif - envl.rgb *= albedo; + envl.rgb *= diffuseIBL(albedo, roughness, f0, dotNV); #ifdef _Brdf envl.rgb *= 1.0 - F; //LV: We should take refracted light into account @@ -146,7 +146,7 @@ void main() { envl.rgb *= envmapStrength * voxelgiEnv * occspec.x; vec4 trace = traceDiffuse(P, n, voxels, clipmaps); - vec3 color = trace.rgb * albedo * (1.0 - F); + vec3 color = trace.rgb * diffuseIBL(albedo, roughness, f0, dotNV) * (1.0 - F); color += envl * (1.0 - trace.a); imageStore(voxels_diffuse, ivec2(pixel), vec4(color, 1.0)); diff --git a/leenkx/blender/lnx/make_renderpath.py b/leenkx/blender/lnx/make_renderpath.py index e049db20..6eee2aca 100644 --- a/leenkx/blender/lnx/make_renderpath.py +++ b/leenkx/blender/lnx/make_renderpath.py @@ -173,6 +173,19 @@ def add_world_defs(): wrd.world_defs += '_Brdf' assets.add_khafile_def("lnx_brdf") + if rpdat.lnx_diffuse_model == 'Burley': + wrd.world_defs += '_BurleyDiffuse' + assets.add_khafile_def('lnx_burley_diffuse') + elif rpdat.lnx_diffuse_model == 'EON': + wrd.world_defs += '_EONDiffuse' + assets.add_khafile_def('lnx_eon_diffuse') + elif rpdat.lnx_diffuse_model == 'Gotanda': + wrd.world_defs += '_GotandaDiffuse' + assets.add_khafile_def('lnx_gotanda_diffuse') + elif rpdat.lnx_diffuse_model == 'Chan': + wrd.world_defs += '_ChanDiffuse' + assets.add_khafile_def('lnx_chan_diffuse') + def build(): rpdat = lnx.utils.get_rp() project_path = lnx.utils.get_fp() diff --git a/leenkx/blender/lnx/material/make_mesh.py b/leenkx/blender/lnx/material/make_mesh.py index 3bb518f5..e60cd896 100644 --- a/leenkx/blender/lnx/material/make_mesh.py +++ b/leenkx/blender/lnx/material/make_mesh.py @@ -737,7 +737,7 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False): if '_Rad' in wrd.world_defs: frag.write('prefilteredColor = pow(prefilteredColor, vec3(2.2));') - frag.write('envl *= albedo;') + frag.write('envl *= diffuseIBL(albedo, roughness, f0, dotNV);') if '_Brdf' in wrd.world_defs: frag.write('envl.rgb *= 1.0 - F;') @@ -771,7 +771,7 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False): if '_VoxelGI' in wrd.world_defs: frag.write('vec4 diffuse_indirect = traceDiffuse(wposition, n, voxels, clipmaps);') - frag.write('indirect = (diffuse_indirect.rgb * albedo * (1.0 - F) + envl * (1.0 - diffuse_indirect.a)) * voxelgiDiff;') + frag.write('indirect = (diffuse_indirect.rgb * diffuseIBL(albedo, roughness, f0, dotNV) * (1.0 - F) + envl * (1.0 - diffuse_indirect.a)) * voxelgiDiff;') frag.write('if (roughness < 1.0 && specular > 0.0) {') frag.write(' indirect += traceSpecular(wposition, n, voxels, voxelsSDF, vVec, roughness * roughness, clipmaps, gl_FragCoord.xy, velocity).rgb * F * voxelgiRefl;') frag.write('}') @@ -847,7 +847,7 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False): 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(' diffuseBRDF(albedo, roughness, f0, sdotNL, dotNV, sdotVH) + 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') @@ -858,7 +858,7 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False): 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;') + frag.write('direct += (diffuseBRDF(albedo, roughness, f0, sdotNL, dotNV, sdotVH) + specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * specular) * sunCol * svisibility;') # sun if '_SinglePoint' in wrd.world_defs: @@ -880,7 +880,8 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False): else: frag.add_uniform('vec2 lightProj', link='_lightPlaneProj', included=True) frag.add_uniform('samplerCubeShadow shadowMapPoint[1]', included=True) - frag.add_uniform('samplerCube shadowMapPointTransparent[1]', included=True) + if is_transparent_shadows: + frag.add_uniform('samplerCube shadowMapPointTransparent[1]', included=True) frag.write('direct += sampleLight(') frag.write(' wposition, n, vVec, dotNV, pointPos, pointCol, albedo, roughness, specular, f0') if is_shadows: diff --git a/leenkx/blender/lnx/material/make_voxel.py b/leenkx/blender/lnx/material/make_voxel.py index c533ca78..9a975b43 100644 --- a/leenkx/blender/lnx/material/make_voxel.py +++ b/leenkx/blender/lnx/material/make_voxel.py @@ -411,7 +411,8 @@ def make_gi(context_id): frag.add_uniform('vec4 pointLightDataArray[maxLightsCluster]', link='_pointLightsAtlasArray', included=True) else: frag.add_uniform('samplerCubeShadow shadowMapPoint[4]', included=True) - frag.add_uniform('samplerCube shadowMapPointTransparent[4]', included=True) + if is_transparent_shadows: + frag.add_uniform('samplerCube shadowMapPointTransparent[4]', included=True) vert.add_out('vec4 wvppositionGeom') vert.add_uniform('mat4 VP', '_viewProjectionMatrix') diff --git a/leenkx/blender/lnx/props_renderpath.py b/leenkx/blender/lnx/props_renderpath.py index da3ed14c..c90080b3 100644 --- a/leenkx/blender/lnx/props_renderpath.py +++ b/leenkx/blender/lnx/props_renderpath.py @@ -486,6 +486,14 @@ class LnxRPListItem(bpy.types.PropertyGroup): ('Solid', 'Solid', 'Solid'), ], name="Materials", description="Material builder", default='Full', update=update_material_model) + lnx_diffuse_model: EnumProperty( + items=[('Lambert', 'Lambert', 'Lambert'), + ('Burley', 'Burley', 'Burley with Frostbite energy renormalization'), + ('EON', 'Oren-Nayar', 'Energy preserving Oren Nayar with multi scatter compensation'), + ('Gotanda', 'Gotanda GGX Diffuse', 'Microfacet GGX diffuse with Fresnel and visibility'), + ('Chan', 'Chan Retroreflective', 'GGX microfacet diffuse with retroreflective lobe'), + ], + name="Diffuse BRDF", description="Diffuse BRDF model", default='Burley', update=update_material_model) lnx_rp_displacement: EnumProperty( items=[('Off', 'Off', 'Off'), ('Vertex', 'Vertex', 'Vertex'), diff --git a/leenkx/blender/lnx/props_ui.py b/leenkx/blender/lnx/props_ui.py index cedb3b0d..edf725fe 100644 --- a/leenkx/blender/lnx/props_ui.py +++ b/leenkx/blender/lnx/props_ui.py @@ -1696,6 +1696,7 @@ class LNX_PT_RenderPathRendererPanel(bpy.types.Panel): if rpdat.rp_renderer == 'Forward': layout.prop(rpdat, 'rp_depthprepass') layout.prop(rpdat, 'lnx_material_model') + layout.prop(rpdat, 'lnx_diffuse_model') layout.prop(rpdat, 'rp_translucency_state') layout.prop(rpdat, 'rp_overlays_state') layout.prop(rpdat, 'rp_decals_state') From 6d07e70b11d63ead214512a6ab3231c3d903d2a0 Mon Sep 17 00:00:00 2001 From: Onek8 Date: Tue, 8 Sep 2026 22:34:51 -0700 Subject: [PATCH 4/4] Hashlink Compile - Curve/Console --- leenkx/Sources/iron/object/CurveObject.hx | 9 +++++---- leenkx/Sources/leenkx/trait/internal/DebugConsole.hx | 2 ++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/leenkx/Sources/iron/object/CurveObject.hx b/leenkx/Sources/iron/object/CurveObject.hx index 15d495c7..88c26466 100644 --- a/leenkx/Sources/iron/object/CurveObject.hx +++ b/leenkx/Sources/iron/object/CurveObject.hx @@ -84,7 +84,7 @@ class CurveObject extends Object { }; for (spline in data.splines) { - var newSpline = { + var newSpline: TSpline = { points: [], closed: spline.closed, resolution: spline.resolution, @@ -441,7 +441,7 @@ class CurveObject extends Object { for (splineIndex in 0...splinesLength) { var spline = data.splines[splineIndex]; - var matIdx = spline.material_index != null ? spline.material_index : 0; + var matIdx = spline.material_index; if (!indicesByMaterial.exists(matIdx)) indicesByMaterial.set(matIdx, []); var indices = indicesByMaterial.get(matIdx); @@ -704,7 +704,7 @@ class CurveObject extends Object { for (splineIndex in 0...splinesLength) { var spline = data.splines[splineIndex]; - var matIdx = spline.material_index != null ? spline.material_index : 0; + var matIdx = spline.material_index; if (!indicesByMaterial.exists(matIdx)) indicesByMaterial.set(matIdx, []); var indices = indicesByMaterial.get(matIdx); @@ -1032,7 +1032,8 @@ class CurveObject extends Object { if (basePos == null) return null; var baseVertCount = Std.int(basePos.length / 4); - var baseScale = baseRaw.scale_pos; + var baseScale: kha.FastFloat = 1.0; + if (baseRaw.scale_pos != null) baseScale = baseRaw.scale_pos; var minVal = 1e10; var maxVal = -1e10; diff --git a/leenkx/Sources/leenkx/trait/internal/DebugConsole.hx b/leenkx/Sources/leenkx/trait/internal/DebugConsole.hx index b61743fb..0d688f62 100644 --- a/leenkx/Sources/leenkx/trait/internal/DebugConsole.hx +++ b/leenkx/Sources/leenkx/trait/internal/DebugConsole.hx @@ -968,6 +968,7 @@ class DebugConsole extends Trait { ui.unindent(); } + #if js if (ui.panel(Id.handle({selected: false}), "Console")) { ui.indent(); var t = ui.textInput(Id.handle()); @@ -977,6 +978,7 @@ class DebugConsole extends Trait { } ui.unindent(); } + #end } if (ui.tab(htab, lastTraces[0] == "" ? "Console" : lastTraces[0].substr(0, 20))) { #if js