From 210d5ea532cf128b1aa329a4571bf6349b9200f3 Mon Sep 17 00:00:00 2001 From: Onek8 Date: Wed, 21 May 2025 22:39:52 +0000 Subject: [PATCH] Update leenkx/blender/lnx/material/make_finalize.py --- leenkx/blender/lnx/material/make_finalize.py | 321 ++++++++++--------- 1 file changed, 166 insertions(+), 155 deletions(-) diff --git a/leenkx/blender/lnx/material/make_finalize.py b/leenkx/blender/lnx/material/make_finalize.py index afdca57..d549fff 100644 --- a/leenkx/blender/lnx/material/make_finalize.py +++ b/leenkx/blender/lnx/material/make_finalize.py @@ -1,155 +1,166 @@ -import bpy - -import lnx -import lnx.material.mat_state as mat_state -import lnx.material.make_tess as make_tess -from lnx.material.shader import ShaderContext - -if lnx.is_reload(__name__): - mat_state = lnx.reload_module(mat_state) - make_tess = lnx.reload_module(make_tess) - lnx.material.shader = lnx.reload_module(lnx.material.shader) - from lnx.material.shader import ShaderContext -else: - lnx.enable_reload(__name__) - - -def make(con_mesh: ShaderContext): - vert = con_mesh.vert - frag = con_mesh.frag - geom = con_mesh.geom - tesc = con_mesh.tesc - tese = con_mesh.tese - - # Additional values referenced in cycles - # TODO: enable from cycles.py - if frag.contains('dotNV') and not frag.contains('float dotNV'): - frag.write_init('float dotNV = max(dot(n, vVec), 0.0);') - - # n is not always defined yet (in some shadowmap shaders e.g.) - if not frag.contains('vec3 n'): - vert.add_out('vec3 wnormal') - billboard = mat_state.material.lnx_billboard - if billboard == 'spherical': - vert.add_uniform('mat3 N', '_normalMatrixSphere') - elif billboard == 'cylindrical': - vert.add_uniform('mat3 N', '_normalMatrixCylinder') - else: - vert.add_uniform('mat3 N', '_normalMatrix') - vert.write_attrib('wnormal = normalize(N * vec3(nor.xy, pos.w));') - frag.write_attrib('vec3 n = normalize(wnormal);') - - # If not yet added, add nor vertex data - vertex_elems = con_mesh.data['vertex_elements'] - has_normals = False - for elem in vertex_elems: - if elem['name'] == 'nor': - has_normals = True - break - if not has_normals: - vertex_elems.append({'name': 'nor', 'data': 'short2norm'}) - - write_wpos = False - if frag.contains('vVec') and not frag.contains('vec3 vVec'): - if tese is not None: - tese.add_out('vec3 eyeDir') - tese.add_uniform('vec3 eye', '_cameraPosition') - tese.write('eyeDir = eye - wposition;') - - else: - if not vert.contains('wposition'): - write_wpos = True - vert.add_out('vec3 eyeDir') - vert.add_uniform('vec3 eye', '_cameraPosition') - vert.write('eyeDir = eye - wposition;') - frag.write_attrib('vec3 vVec = normalize(eyeDir);') - - export_wpos = False - if frag.contains('wposition') and not frag.contains('vec3 wposition'): - export_wpos = True - if tese is not None: - export_wpos = True - if vert.contains('wposition'): - write_wpos = True - - if export_wpos: - vert.add_uniform('mat4 W', '_worldMatrix') - vert.add_out('vec3 wposition') - vert.write('wposition = vec4(W * spos).xyz;') - elif write_wpos: - vert.add_uniform('mat4 W', '_worldMatrix') - vert.write_attrib('vec3 wposition = vec4(W * spos).xyz;') - - frag_mpos = (frag.contains('mposition') and not frag.contains('vec3 mposition')) or vert.contains('mposition') - if frag_mpos: - vert.add_out('vec3 mposition') - vert.add_uniform('float posUnpack', link='_posUnpack') - vert.write_attrib('mposition = spos.xyz * posUnpack;') - - if tese is not None: - if frag_mpos: - make_tess.interpolate(tese, 'mposition', 3, declare_out=True) - elif tese.contains('mposition') and not tese.contains('vec3 mposition'): - vert.add_out('vec3 mposition') - vert.write_pre = True - vert.add_uniform('float posUnpack', link='_posUnpack') - vert.write('mposition = spos.xyz * posUnpack;') - vert.write_pre = False - make_tess.interpolate(tese, 'mposition', 3, declare_out=False) - - frag_bpos = (frag.contains('bposition') and not frag.contains('vec3 bposition')) or vert.contains('bposition') - if frag_bpos: - vert.add_out('vec3 bposition') - vert.add_uniform('vec3 dim', link='_dim') - vert.add_uniform('vec3 hdim', link='_halfDim') - vert.add_uniform('float posUnpack', link='_posUnpack') - vert.write_attrib('bposition = (spos.xyz * posUnpack + hdim) / dim;') - vert.write_attrib('if (dim.z == 0) bposition.z = 0;') - vert.write_attrib('if (dim.y == 0) bposition.y = 0;') - vert.write_attrib('if (dim.x == 0) bposition.x = 0;') - - if tese is not None: - if frag_bpos: - make_tess.interpolate(tese, 'bposition', 3, declare_out=True) - elif tese.contains('bposition') and not tese.contains('vec3 bposition'): - vert.add_out('vec3 bposition') - vert.add_uniform('vec3 dim', link='_dim') - vert.add_uniform('vec3 hdim', link='_halfDim') - vert.add_uniform('float posUnpack', link='_posUnpack') - vert.write_attrib('bposition = (spos.xyz * posUnpack + hdim) / dim;') - make_tess.interpolate(tese, 'bposition', 3, declare_out=False) - - frag_wtan = (frag.contains('wtangent') and not frag.contains('vec3 wtangent')) or vert.contains('wtangent') - if frag_wtan: - # Indicate we want tang attrib in finalizer to prevent TBN generation - con_mesh.add_elem('tex', 'short2norm') - con_mesh.add_elem('tang', 'short4norm') - vert.add_out('vec3 wtangent') - vert.write_pre = True - vert.write('wtangent = normalize(N * tang.xyz);') - vert.write_pre = False - - if tese is not None: - if frag_wtan: - make_tess.interpolate(tese, 'wtangent', 3, declare_out=True) - elif tese.contains('wtangent') and not tese.contains('vec3 wtangent'): - vert.add_out('vec3 wtangent') - vert.write_pre = True - vert.write('wtangent = normalize(N * tang.xyz);') - vert.write_pre = False - make_tess.interpolate(tese, 'wtangent', 3, declare_out=False) - - if frag.contains('vVecCam'): - vert.add_out('vec3 eyeDirCam') - vert.add_uniform('mat4 WV', '_worldViewMatrix') - vert.write('eyeDirCam = vec4(WV * spos).xyz; eyeDirCam.z *= -1;') - frag.write_attrib('vec3 vVecCam = normalize(eyeDirCam);') - - if frag.contains('nAttr'): - vert.add_out('vec3 nAttr') - vert.write_attrib('nAttr = vec3(nor.xy, pos.w);') - - wrd = bpy.data.worlds['Lnx'] - if '_Legacy' in wrd.world_defs: - frag.replace('sampler2DShadow', 'sampler2D') - frag.replace('samplerCubeShadow', 'samplerCube') +import bpy + +import lnx +import lnx.material.mat_state as mat_state +import lnx.material.make_tess as make_tess +from lnx.material.shader import ShaderContext + +if lnx.is_reload(__name__): + mat_state = lnx.reload_module(mat_state) + make_tess = lnx.reload_module(make_tess) + lnx.material.shader = lnx.reload_module(lnx.material.shader) + from lnx.material.shader import ShaderContext +else: + lnx.enable_reload(__name__) + + +def make(con_mesh: ShaderContext): + vert = con_mesh.vert + frag = con_mesh.frag + geom = con_mesh.geom + tesc = con_mesh.tesc + tese = con_mesh.tese + + # Additional values referenced in cycles + # TODO: enable from cycles.py + if frag.contains('dotNV') and not frag.contains('float dotNV'): + frag.write_init('float dotNV = max(dot(n, vVec), 0.0);') + + # n is not always defined yet (in some shadowmap shaders e.g.) + if not frag.contains('vec3 n'): + vert.add_out('vec3 wnormal') + billboard = mat_state.material.lnx_billboard + if billboard == 'spherical': + vert.add_uniform('mat3 N', '_normalMatrixSphere') + elif billboard == 'cylindrical': + vert.add_uniform('mat3 N', '_normalMatrixCylinder') + else: + vert.add_uniform('mat3 N', '_normalMatrix') + vert.write_attrib('wnormal = normalize(N * vec3(nor.xy, pos.w));') + frag.write_attrib('vec3 n = normalize(wnormal);') + + # If not yet added, add nor vertex data + vertex_elems = con_mesh.data['vertex_elements'] + has_normals = False + for elem in vertex_elems: + if elem['name'] == 'nor': + has_normals = True + break + if not has_normals: + vertex_elems.append({'name': 'nor', 'data': 'short2norm'}) + + write_wpos = False + export_wpos = False + if frag.contains('wposition') and not frag.contains('vec3 wposition'): + export_wpos = True + if tese is not None: + export_wpos = True + if vert.contains('wposition'): + write_wpos = True + + + + + if frag.contains('vVec') and not frag.contains('vec3 vVec'): + if tese is not None: + tese.add_out('vec3 eyeDir') + tese.add_uniform('vec3 eye', '_cameraPosition') + tese.write('eyeDir = eye - wposition;') + + else: + if not vert.contains('wposition'): + write_wpos = True + vert.add_out('vec3 eyeDir') + vert.add_uniform('vec3 eye', '_cameraPosition') + vert.write('eyeDir = eye - wposition;') + frag.write_attrib('vec3 vVec = normalize(eyeDir);') + + export_wpos = False + if frag.contains('wposition') and not frag.contains('vec3 wposition'): + export_wpos = True + if tese is not None: + export_wpos = True + if vert.contains('wposition'): + write_wpos = True + + if export_wpos: + vert.add_uniform('mat4 W', '_worldMatrix') + vert.add_out('vec3 wposition') + vert.write('wposition = vec4(W * spos).xyz;') + elif write_wpos: + vert.add_uniform('mat4 W', '_worldMatrix') + vert.write_attrib('vec3 wposition = vec4(W * spos).xyz;') + + frag_mpos = (frag.contains('mposition') and not frag.contains('vec3 mposition')) or vert.contains('mposition') + if frag_mpos: + vert.add_out('vec3 mposition') + vert.add_uniform('float posUnpack', link='_posUnpack') + vert.write_attrib('mposition = spos.xyz * posUnpack;') + + if tese is not None: + if frag_mpos: + make_tess.interpolate(tese, 'mposition', 3, declare_out=True) + elif tese.contains('mposition') and not tese.contains('vec3 mposition'): + vert.add_out('vec3 mposition') + vert.write_pre = True + vert.add_uniform('float posUnpack', link='_posUnpack') + vert.write('mposition = spos.xyz * posUnpack;') + vert.write_pre = False + make_tess.interpolate(tese, 'mposition', 3, declare_out=False) + + frag_bpos = (frag.contains('bposition') and not frag.contains('vec3 bposition')) or vert.contains('bposition') + if frag_bpos: + vert.add_out('vec3 bposition') + vert.add_uniform('vec3 dim', link='_dim') + vert.add_uniform('vec3 hdim', link='_halfDim') + vert.add_uniform('float posUnpack', link='_posUnpack') + vert.write_attrib('bposition = (spos.xyz * posUnpack + hdim) / dim;') + vert.write_attrib('if (dim.z == 0) bposition.z = 0;') + vert.write_attrib('if (dim.y == 0) bposition.y = 0;') + vert.write_attrib('if (dim.x == 0) bposition.x = 0;') + + if tese is not None: + if frag_bpos: + make_tess.interpolate(tese, 'bposition', 3, declare_out=True) + elif tese.contains('bposition') and not tese.contains('vec3 bposition'): + vert.add_out('vec3 bposition') + vert.add_uniform('vec3 dim', link='_dim') + vert.add_uniform('vec3 hdim', link='_halfDim') + vert.add_uniform('float posUnpack', link='_posUnpack') + vert.write_attrib('bposition = (spos.xyz * posUnpack + hdim) / dim;') + make_tess.interpolate(tese, 'bposition', 3, declare_out=False) + + frag_wtan = (frag.contains('wtangent') and not frag.contains('vec3 wtangent')) or vert.contains('wtangent') + if frag_wtan: + # Indicate we want tang attrib in finalizer to prevent TBN generation + con_mesh.add_elem('tex', 'short2norm') + con_mesh.add_elem('tang', 'short4norm') + vert.add_out('vec3 wtangent') + vert.write_pre = True + vert.write('wtangent = normalize(N * tang.xyz);') + vert.write_pre = False + + if tese is not None: + if frag_wtan: + make_tess.interpolate(tese, 'wtangent', 3, declare_out=True) + elif tese.contains('wtangent') and not tese.contains('vec3 wtangent'): + vert.add_out('vec3 wtangent') + vert.write_pre = True + vert.write('wtangent = normalize(N * tang.xyz);') + vert.write_pre = False + make_tess.interpolate(tese, 'wtangent', 3, declare_out=False) + + if frag.contains('vVecCam'): + vert.add_out('vec3 eyeDirCam') + vert.add_uniform('mat4 WV', '_worldViewMatrix') + vert.write('eyeDirCam = vec4(WV * spos).xyz; eyeDirCam.z *= -1;') + frag.write_attrib('vec3 vVecCam = normalize(eyeDirCam);') + + if frag.contains('nAttr'): + vert.add_out('vec3 nAttr') + vert.write_attrib('nAttr = vec3(nor.xy, pos.w);') + + wrd = bpy.data.worlds['Lnx'] + if '_Legacy' in wrd.world_defs: + frag.replace('sampler2DShadow', 'sampler2D') + frag.replace('samplerCubeShadow', 'samplerCube')