forked from LeenkxTeam/LNXSDK
Full BSDF
This commit is contained in:
@ -2514,6 +2514,9 @@ class LeenkxExporter:
|
||||
# Ensure the same order for merging materials
|
||||
self.material_array.sort(key=lambda x: x.name)
|
||||
|
||||
from lnx.material import mat_state
|
||||
mat_state.next_ext_mat_id = 3
|
||||
|
||||
if wrd.lnx_batch_materials:
|
||||
mat_users = self.material_to_object_dict
|
||||
mat_lnxusers = self.material_to_lnx_object_dict
|
||||
@ -2526,9 +2529,6 @@ class LeenkxExporter:
|
||||
decals_used = False
|
||||
sss_used = False
|
||||
|
||||
from lnx.material import mat_state
|
||||
mat_state.next_ext_mat_id = 3
|
||||
|
||||
for material in self.material_array:
|
||||
# If the material is unlinked, material becomes None
|
||||
if material is None:
|
||||
|
||||
@ -247,7 +247,7 @@ def check_link(
|
||||
included based on the given defines (`defs`). If that is the case,
|
||||
the found link is written to the `out` dictionary.
|
||||
"""
|
||||
for link in source_context["links"]:
|
||||
for link in source_context.get("links", []):
|
||||
if link["name"] == cid:
|
||||
valid_link = True
|
||||
|
||||
|
||||
@ -133,7 +133,6 @@ def add_world_defs():
|
||||
assets.add_shader_external(lnx.utils.get_sdk_path() + '/leenkx/Shaders/voxel_offsetprev/voxel_offsetprev.comp.glsl')
|
||||
assets.add_shader_external(lnx.utils.get_sdk_path() + '/leenkx/Shaders/voxel_temporal/voxel_temporal.comp.glsl')
|
||||
assets.add_shader_external(lnx.utils.get_sdk_path() + '/leenkx/Shaders/voxel_sdf_jumpflood/voxel_sdf_jumpflood.comp.glsl')
|
||||
#wrd.world_defs += "_VoxelCones" + rpdat.lnx_voxelgi_cones
|
||||
if rpdat.lnx_voxelgi_shadows and (point_lights > 0 or '_Sun' in wrd.world_defs):
|
||||
wrd.world_defs += '_VoxelShadow'
|
||||
assets.add_khafile_def('lnx_voxelgi_shadows')
|
||||
@ -173,9 +172,6 @@ def add_world_defs():
|
||||
wrd.world_defs += '_Brdf'
|
||||
assets.add_khafile_def("lnx_brdf")
|
||||
|
||||
if '_Anisotropy' in wrd.world_defs:
|
||||
assets.add_khafile_def('lnx_anisotropy')
|
||||
|
||||
def build():
|
||||
rpdat = lnx.utils.get_rp()
|
||||
project_path = lnx.utils.get_fp()
|
||||
@ -237,7 +233,7 @@ def build():
|
||||
assets.add_khafile_def('rp_compositornodes')
|
||||
compo_depth = False
|
||||
# wrd.compo_defs += ''
|
||||
if rpdat.lnx_tonemap != 'Off':
|
||||
if rpdat.lnx_tonemap != 'Off' and not state.is_viewport:
|
||||
wrd.compo_defs += '_CTone' + rpdat.lnx_tonemap
|
||||
if rpdat.lnx_dithering != 'Off':
|
||||
wrd.compo_defs += '_CDithering' + rpdat.lnx_dithering
|
||||
@ -444,7 +440,8 @@ def build():
|
||||
|
||||
if rpdat.rp_sss:
|
||||
assets.add_khafile_def('rp_sss')
|
||||
wrd.world_defs += '_SSS'
|
||||
if '_SSS' not in wrd.world_defs:
|
||||
wrd.world_defs += '_SSS'
|
||||
assets.add_shader_pass('sss_pass')
|
||||
|
||||
if (rpdat.rp_ssr and rpdat.lnx_ssr_half_res) or (rpdat.rp_ssao and rpdat.lnx_ssao_half_res) or (rpdat.rp_ssgi and rpdat.lnx_ssgi_half_res) or rpdat.rp_voxels != "Off":
|
||||
@ -487,13 +484,55 @@ def build():
|
||||
|
||||
if ignoreIrr:
|
||||
wrd.world_defs += '_IgnoreIrr'
|
||||
# TODO: avoid the prescan correctly
|
||||
if bpy.app.version >= (4, 0, 0):
|
||||
coat_name = 'Coat Weight'
|
||||
sheen_name = 'Sheen Weight'
|
||||
subsurf_name = 'Subsurface Weight'
|
||||
trans_name = 'Transmission Weight'
|
||||
else:
|
||||
coat_name = 'Clearcoat'
|
||||
sheen_name = 'Sheen'
|
||||
subsurf_name = 'Subsurface'
|
||||
trans_name = 'Transmission'
|
||||
for mat in bpy.data.materials:
|
||||
if mat.node_tree is None:
|
||||
continue
|
||||
for node in mat.node_tree.nodes:
|
||||
if node.type == 'BSDF_PRINCIPLED':
|
||||
coat_socket = node.inputs.get(coat_name)
|
||||
if coat_socket is not None and (coat_socket.is_linked or coat_socket.default_value > 0.0):
|
||||
if '_ClearCoat' not in wrd.world_defs:
|
||||
wrd.world_defs += '_ClearCoat'
|
||||
aniso_socket = node.inputs.get('Anisotropic')
|
||||
if aniso_socket is not None and (aniso_socket.is_linked or aniso_socket.default_value > 0.0):
|
||||
if '_Anisotropy' not in wrd.world_defs:
|
||||
wrd.world_defs += '_Anisotropy'
|
||||
sheen_socket = node.inputs.get(sheen_name)
|
||||
if sheen_socket is not None and (sheen_socket.is_linked or sheen_socket.default_value > 0.0):
|
||||
if '_Sheen' not in wrd.world_defs:
|
||||
wrd.world_defs += '_Sheen'
|
||||
subsurf_socket = node.inputs.get(subsurf_name)
|
||||
if subsurf_socket is not None and (subsurf_socket.is_linked or subsurf_socket.default_value > 0.0):
|
||||
if '_SSS' not in wrd.world_defs:
|
||||
wrd.world_defs += '_SSS'
|
||||
trans_socket = node.inputs.get(trans_name)
|
||||
if trans_socket is not None and (trans_socket.is_linked or trans_socket.default_value > 0.0):
|
||||
if '_Transmission' not in wrd.world_defs:
|
||||
wrd.world_defs += '_Transmission'
|
||||
elif node.type == 'SUBSURFACE_SCATTERING':
|
||||
if '_SSS' not in wrd.world_defs:
|
||||
wrd.world_defs += '_SSS'
|
||||
|
||||
gbuffer2 = '_Veloc' in wrd.world_defs or '_IgnoreIrr' in wrd.world_defs or '_VoxelGI' in wrd.world_defs or '_VoxelShadow' in wrd.world_defs or '_SSGI' in wrd.world_defs
|
||||
gbuffer2 = '_Veloc' in wrd.world_defs or '_IgnoreIrr' in wrd.world_defs or '_VoxelGI' in wrd.world_defs or '_VoxelShadow' in wrd.world_defs or '_SSGI' in wrd.world_defs or '_Anisotropy' in wrd.world_defs
|
||||
|
||||
if gbuffer2:
|
||||
assets.add_khafile_def('rp_gbuffer2')
|
||||
wrd.world_defs += '_gbuffer2'
|
||||
|
||||
if '_ClearCoat' in wrd.world_defs:
|
||||
assets.add_khafile_def('rp_clearcoat')
|
||||
|
||||
if callback is not None:
|
||||
callback()
|
||||
|
||||
@ -506,7 +545,7 @@ def get_num_gbuffer_rts_deferred()-> int:
|
||||
refraction_flags = {'_SSRefraction', '_VoxelRefract'}
|
||||
found_refraction_flag = False
|
||||
|
||||
for flag in ('_gbuffer2', '_EmissionShaded', '_SSRefraction', '_VoxelRefract'):
|
||||
for flag in ('_gbuffer2', '_EmissionShaded', '_SSRefraction', '_VoxelRefract', '_ClearCoat'):
|
||||
if flag in wrd.world_defs:
|
||||
if flag in refraction_flags and not found_refraction_flag:
|
||||
num += 1
|
||||
@ -514,7 +553,4 @@ def get_num_gbuffer_rts_deferred()-> int:
|
||||
else:
|
||||
num += 1
|
||||
|
||||
if '_Anisotropy' in wrd.world_defs:
|
||||
num += 1
|
||||
|
||||
return num
|
||||
|
||||
@ -192,13 +192,27 @@ def parse(nodes, con: ShaderContext,
|
||||
import re as _re
|
||||
|
||||
def _extract_vec3(s):
|
||||
m = _re.match(r'vec3\s*\(\s*([^,\s\)]+)\s*\)', s)
|
||||
if m and ',' not in m.group(1):
|
||||
v = m.group(1)
|
||||
return v, v, v
|
||||
m = _re.match(r'vec3\s*\(\s*([^,\s]+)\s*,\s*([^,\s]+)\s*,\s*([^,\s\)]+)', s)
|
||||
if m:
|
||||
return m.group(1), m.group(2), m.group(3)
|
||||
s = s.strip()
|
||||
m = _re.match(r'vec3\s*\((.*)\)\s*$', s)
|
||||
if not m:
|
||||
return '1.0', '1.0', '1.0'
|
||||
inner = m.group(1).strip()
|
||||
parts = []
|
||||
depth = 0
|
||||
start = 0
|
||||
for i, ch in enumerate(inner):
|
||||
if ch == '(':
|
||||
depth += 1
|
||||
elif ch == ')':
|
||||
depth -= 1
|
||||
elif ch == ',' and depth == 0:
|
||||
parts.append(inner[start:i].strip())
|
||||
start = i + 1
|
||||
parts.append(inner[start:].strip())
|
||||
if len(parts) == 1:
|
||||
return parts[0], parts[0], parts[0]
|
||||
if len(parts) == 3:
|
||||
return parts[0], parts[1], parts[2]
|
||||
return '1.0', '1.0', '1.0'
|
||||
|
||||
def _try_float(val_str, default=0.0):
|
||||
@ -209,14 +223,10 @@ def parse(nodes, con: ShaderContext,
|
||||
|
||||
_sss_r, _sss_g, _sss_b = _extract_vec3(state.out_subsurface_radius)
|
||||
_sss_scale = state.out_subsurface_scale
|
||||
_sss_scale_f = _try_float(_sss_scale, 0.05)
|
||||
if _sss_scale_f != 1.0:
|
||||
_sss_r = str(_try_float(_sss_r, 1.0) * _sss_scale_f)
|
||||
_sss_g = str(_try_float(_sss_g, 0.2) * _sss_scale_f)
|
||||
_sss_b = str(_try_float(_sss_b, 0.1) * _sss_scale_f)
|
||||
|
||||
_sheen_tint_r, _sheen_tint_g, _sheen_tint_b = _extract_vec3(state.out_sheen_tint)
|
||||
_coat_tint_r, _coat_tint_g, _coat_tint_b = _extract_vec3(state.out_coat_tint)
|
||||
_spec_tint_r, _spec_tint_g, _spec_tint_b = _extract_vec3(state.out_specular_tint)
|
||||
_sss_color_r, _sss_color_g, _sss_color_b = _extract_vec3(state.out_subsurface_color)
|
||||
|
||||
mat_state.features = {
|
||||
@ -233,6 +243,7 @@ def parse(nodes, con: ShaderContext,
|
||||
'sheenTintB': _sheen_tint_b,
|
||||
'subsurface': state.out_subsurface,
|
||||
'subsurfaceAnisotropy': state.out_subsurface_anisotropy,
|
||||
'subsurfaceScale': _sss_scale,
|
||||
'subsurfaceRadiusR': _sss_r,
|
||||
'subsurfaceRadiusG': _sss_g,
|
||||
'subsurfaceRadiusB': _sss_b,
|
||||
@ -245,6 +256,9 @@ def parse(nodes, con: ShaderContext,
|
||||
'transmissionRough': state.out_transmission_rough,
|
||||
'ior': state.out_ior,
|
||||
'thinWall': state.out_thin_wall,
|
||||
'specularTintR': _spec_tint_r,
|
||||
'specularTintG': _spec_tint_g,
|
||||
'specularTintB': _spec_tint_b,
|
||||
}
|
||||
state = None
|
||||
|
||||
@ -751,11 +765,11 @@ def vector_curve(name, fac, points):
|
||||
# Map vector
|
||||
return 'mix({0}[{1}], {0}[{1} + 1], ({2} - {3}[{1}]) * (1.0 / ({3}[{1} + 1] - {3}[{1}]) ))'.format(ys_var, index_var, fac_var, facs_var)
|
||||
|
||||
def write_normal(inp):
|
||||
def write_normal(inp, target_var='n'):
|
||||
if inp.is_linked and inp.links[0].from_node.type != 'GROUP_INPUT':
|
||||
normal_res = parse_vector_input(inp)
|
||||
if normal_res != None:
|
||||
state.curshader.write('n = {0};'.format(normal_res))
|
||||
state.curshader.write('{0} = {1};'.format(target_var, normal_res))
|
||||
|
||||
|
||||
def is_parsed(node_store_name: str):
|
||||
|
||||
@ -77,17 +77,12 @@ def parse_mixshader(node: bpy.types.ShaderNodeMixShader, out_socket: NodeSocket,
|
||||
state.curshader.write('{0}float {1} = 1.0 - {2};'.format(prefix, fac_inv_var, fac_var))
|
||||
|
||||
mat_state.emission_type = mat_state.EmissionType.NO_EMISSION
|
||||
sss_before_1 = mat_state.needs_sss
|
||||
o1 = c.parse_shader_input(node.inputs[1])
|
||||
sss_1 = mat_state.needs_sss
|
||||
ek1 = mat_state.emission_type
|
||||
|
||||
mat_state.emission_type = mat_state.EmissionType.NO_EMISSION
|
||||
mat_state.needs_sss = sss_before_1 # Reset to state before parsing input 1
|
||||
o2 = c.parse_shader_input(node.inputs[2])
|
||||
sss_2 = mat_state.needs_sss
|
||||
ek2 = mat_state.emission_type
|
||||
mat_state.needs_sss = sss_1 or sss_2
|
||||
|
||||
if state.parse_surface:
|
||||
fm = '{0} * {3} + {1} * {2}' # fac mix template: a*fac_inv + b*fac
|
||||
@ -126,17 +121,12 @@ def parse_mixshader(node: bpy.types.ShaderNodeMixShader, out_socket: NodeSocket,
|
||||
|
||||
def parse_addshader(node: bpy.types.ShaderNodeAddShader, out_socket: NodeSocket, state: ParserState) -> None:
|
||||
mat_state.emission_type = mat_state.EmissionType.NO_EMISSION
|
||||
sss_before_1 = mat_state.needs_sss
|
||||
o1 = c.parse_shader_input(node.inputs[0])
|
||||
sss_1 = mat_state.needs_sss
|
||||
ek1 = mat_state.emission_type
|
||||
|
||||
mat_state.emission_type = mat_state.EmissionType.NO_EMISSION
|
||||
mat_state.needs_sss = sss_before_1 # Reset to state before parsing input 0
|
||||
o2 = c.parse_shader_input(node.inputs[1])
|
||||
sss_2 = mat_state.needs_sss
|
||||
ek2 = mat_state.emission_type
|
||||
mat_state.needs_sss = sss_1 or sss_2
|
||||
|
||||
if state.parse_surface:
|
||||
am = '{0} * 0.5 + {1} * 0.5' # add mix template (average)
|
||||
@ -179,8 +169,6 @@ if bpy.app.version < (2, 91, 0):
|
||||
if state.parse_surface:
|
||||
c.write_normal(node.inputs['Normal'])
|
||||
state.out_basecol = c.parse_vector_input(node.inputs['Base Color'])
|
||||
if node.inputs[SUBSURFACE].is_linked or node.inputs[SUBSURFACE].default_value > 0.0:
|
||||
mat_state.needs_sss = True
|
||||
state.out_subsurface = c.parse_value_input(node.inputs[SUBSURFACE])
|
||||
state.out_subsurface_radius = c.parse_vector_input(node.inputs[SUBSURFACE_RADIUS])
|
||||
state.out_subsurface_color = c.parse_vector_input(node.inputs[SUBSURFACE_COLOR])
|
||||
@ -194,6 +182,9 @@ if bpy.app.version < (2, 91, 0):
|
||||
state.out_sheen_tint = 'vec3({})'.format(c.parse_value_input(node.inputs[SHEEN_TINT]))
|
||||
state.out_clearcoat = c.parse_value_input(node.inputs[CLEARCOAT])
|
||||
state.out_clearcoat_rough = c.parse_value_input(node.inputs[CLEARCOAT_ROUGHNESS])
|
||||
coat_normal_socket = node.inputs.get(CLEARCOAT_NORMAL)
|
||||
if coat_normal_socket is not None:
|
||||
c.write_normal(coat_normal_socket, target_var='nCoat')
|
||||
state.out_transmission = c.parse_value_input(node.inputs[TRANSMISSION])
|
||||
trans_rough_socket = node.inputs.get(TRANSMISSION_ROUGHNESS)
|
||||
if trans_rough_socket is not None:
|
||||
@ -216,8 +207,6 @@ if bpy.app.version >= (2, 91, 0) and bpy.app.version < (4, 0, 0):
|
||||
if state.parse_surface:
|
||||
c.write_normal(node.inputs['Normal'])
|
||||
state.out_basecol = c.parse_vector_input(node.inputs['Base Color'])
|
||||
if node.inputs[SUBSURFACE].is_linked or node.inputs[SUBSURFACE].default_value > 0.0:
|
||||
mat_state.needs_sss = True
|
||||
state.out_subsurface = c.parse_value_input(node.inputs[SUBSURFACE])
|
||||
state.out_subsurface_radius = c.parse_vector_input(node.inputs[SUBSURFACE_RADIUS])
|
||||
state.out_subsurface_color = c.parse_vector_input(node.inputs[SUBSURFACE_COLOR])
|
||||
@ -231,6 +220,9 @@ if bpy.app.version >= (2, 91, 0) and bpy.app.version < (4, 0, 0):
|
||||
state.out_sheen_tint = 'vec3({})'.format(c.parse_value_input(node.inputs[SHEEN_TINT]))
|
||||
state.out_clearcoat = c.parse_value_input(node.inputs[CLEARCOAT])
|
||||
state.out_clearcoat_rough = c.parse_value_input(node.inputs[CLEARCOAT_ROUGHNESS])
|
||||
coat_normal_socket = node.inputs.get(CLEARCOAT_NORMAL)
|
||||
if coat_normal_socket is not None:
|
||||
c.write_normal(coat_normal_socket, target_var='nCoat')
|
||||
state.out_transmission = c.parse_value_input(node.inputs[TRANSMISSION])
|
||||
state.out_transmission_rough = c.parse_value_input(node.inputs[TRANSMISSION_ROUGHNESS])
|
||||
state.out_tangent = c.parse_vector_input(node.inputs[TANGENT])
|
||||
@ -256,8 +248,6 @@ if bpy.app.version >= (4, 0, 0):
|
||||
|
||||
sss_input = node.inputs.get(SUBSURFACE)
|
||||
if sss_input is not None:
|
||||
if sss_input.is_linked or sss_input.default_value > 0.0:
|
||||
mat_state.needs_sss = True
|
||||
state.out_subsurface = c.parse_value_input(sss_input)
|
||||
|
||||
sss_radius_input = node.inputs.get(SUBSURFACE_RADIUS)
|
||||
@ -331,6 +321,9 @@ if bpy.app.version >= (4, 0, 0):
|
||||
coat_tint_socket = node.inputs.get(COAT_TINT)
|
||||
if coat_tint_socket is not None:
|
||||
state.out_coat_tint = c.parse_vector_input(coat_tint_socket)
|
||||
coat_normal_socket = node.inputs.get(CLEARCOAT_NORMAL)
|
||||
if coat_normal_socket is not None:
|
||||
c.write_normal(coat_normal_socket, target_var='nCoat')
|
||||
|
||||
trans_socket = node.inputs.get(TRANSMISSION)
|
||||
if trans_socket is not None:
|
||||
@ -507,8 +500,6 @@ def parse_bsdfrefraction(node: bpy.types.ShaderNodeBsdfRefraction, out_socket: N
|
||||
|
||||
def parse_subsurfacescattering(node: bpy.types.ShaderNodeSubsurfaceScattering, out_socket: NodeSocket, state: ParserState) -> None:
|
||||
if state.parse_surface:
|
||||
# Mark that this material needs SSS
|
||||
mat_state.needs_sss = True
|
||||
c.write_normal(node.inputs['Normal'])
|
||||
state.out_basecol = c.parse_vector_input(node.inputs['Color'])
|
||||
state.out_subsurface = c.parse_value_input(node.inputs['Scale'])
|
||||
|
||||
@ -588,7 +588,7 @@ def parse_tex_voronoi(node: bpy.types.ShaderNodeTexVoronoi, out_socket: bpy.type
|
||||
co = 'bposition'
|
||||
|
||||
scale = c.get_value_input(node, ['Scale'])
|
||||
exp = c.get_value_input(node, ['Exponent'])
|
||||
exp = c.get_value_input(node, ['Exponent']) if m == 3 else '1.0'
|
||||
randomness = c.get_value_input(node, ['Randomness'])
|
||||
|
||||
# Color or Position
|
||||
|
||||
@ -64,8 +64,6 @@ def parse(material: Material, mat_data, mat_users: Dict[Material, List[Object]],
|
||||
shader_data_name = material.lnx_custom_material
|
||||
bind_constants = {'mesh': []}
|
||||
bind_textures = {'mesh': []}
|
||||
mat_uses_sss = False
|
||||
|
||||
make_shader.make_instancing_and_skinning(material, mat_users)
|
||||
|
||||
for idx, item in enumerate(material.lnx_bind_textures_list):
|
||||
@ -82,11 +80,11 @@ def parse(material: Material, mat_data, mat_users: Dict[Material, List[Object]],
|
||||
log.warn(f'Material "{material.name}": skipping export of bind texture at slot {idx + 1} ("{item.uniform_name}") with no image selected')
|
||||
|
||||
elif not wrd.lnx_batch_materials or material.name.startswith('lnxdefault'):
|
||||
rpasses, shader_data, shader_data_name, bind_constants, bind_textures, mat_uses_sss = make_shader.build(material, mat_users, mat_lnxusers)
|
||||
rpasses, shader_data, shader_data_name, bind_constants, bind_textures = make_shader.build(material, mat_users, mat_lnxusers)
|
||||
sd = shader_data.sd
|
||||
else:
|
||||
result = mat_batch.get(material)
|
||||
rpasses, shader_data, shader_data_name, bind_constants, bind_textures, mat_uses_sss = result
|
||||
rpasses, shader_data, shader_data_name, bind_constants, bind_textures = result
|
||||
sd = shader_data.sd
|
||||
|
||||
sss_used = False
|
||||
@ -107,74 +105,144 @@ def parse(material: Material, mat_data, mat_users: Dict[Material, List[Object]],
|
||||
if material.lnx_material_id != 0:
|
||||
c['bind_constants'].append({'name': 'materialID', 'intValue': material.lnx_material_id})
|
||||
|
||||
if material.lnx_material_id == 2:
|
||||
wrd.world_defs += '_Hair'
|
||||
|
||||
elif rpdat.rp_sss_state != 'Off':
|
||||
const = {'name': 'materialID'}
|
||||
# Use per-material SSS flag from shader build
|
||||
if mat_uses_sss:
|
||||
const['intValue'] = 2
|
||||
sss_used = True
|
||||
if '_SSS' not in wrd.world_defs:
|
||||
wrd.world_defs += '_SSS'
|
||||
else:
|
||||
const['intValue'] = 0
|
||||
c['bind_constants'].append(const)
|
||||
|
||||
# extended BRDF parameters as bind_constants
|
||||
if rpdat.rp_renderer == 'Deferred':
|
||||
feats = mat_state.features
|
||||
|
||||
def try_float(val_str, default=1.0):
|
||||
import re as _re_mix
|
||||
_mix_re = _re_mix.compile(r'^\s*([+-]?\d*\.?\d+(?:[eE][+-]?\d+)?)\s*\*\s*\w+\s*([+-])\s*([+-]?\d*\.?\d+(?:[eE][+-]?\d+)?)\s*\*\s*\w+\s*$')
|
||||
|
||||
_term_re = _re_mix.compile(r'([+-]?\d*\.?\d+(?:[eE][+-]?\d+)?)\s*\*\s*[^\s*]+(?:\s*\*\s*[^\s*]+)*')
|
||||
_term_pair_re = _re_mix.compile(r'([+-]?\d*\.?\d+(?:[eE][+-]?\d+)?)\s*\*\s*([^\s*]+(?:\s*\*\s*[^\s*]+)*)')
|
||||
|
||||
def _parse_terms(val_str):
|
||||
val_str = str(val_str).strip()
|
||||
pairs = _term_pair_re.findall(val_str)
|
||||
return [(float(c), v.replace(' ', '')) for c, v in pairs]
|
||||
|
||||
def eval_filtered_expr(val_str, filter_str):
|
||||
if val_str is None or filter_str is None:
|
||||
return None
|
||||
filter_terms = _parse_terms(filter_str)
|
||||
if len(filter_terms) < 2:
|
||||
return None
|
||||
filter_map = {}
|
||||
for coeff, var_prod in filter_terms:
|
||||
filter_map[var_prod] = coeff
|
||||
val_terms = _parse_terms(val_str)
|
||||
if len(val_terms) < 2:
|
||||
return None
|
||||
filtered_coeffs = []
|
||||
for coeff, var_prod in val_terms:
|
||||
fc = filter_map.get(var_prod)
|
||||
if fc is not None and fc != 0.0:
|
||||
filtered_coeffs.append(coeff)
|
||||
if not filtered_coeffs:
|
||||
return None
|
||||
if all(c == filtered_coeffs[0] for c in filtered_coeffs):
|
||||
return filtered_coeffs[0]
|
||||
return None
|
||||
|
||||
def eval_mix_expr(val_str):
|
||||
if val_str is None:
|
||||
return None
|
||||
val_str = str(val_str).strip()
|
||||
try:
|
||||
return float(val_str)
|
||||
except (ValueError, TypeError):
|
||||
return default
|
||||
pass
|
||||
m = _mix_re.match(val_str)
|
||||
if m:
|
||||
a = float(m.group(1))
|
||||
op = m.group(2)
|
||||
b = float(m.group(3))
|
||||
if op == '+' and a == b:
|
||||
return a
|
||||
if op == '-' and a == b:
|
||||
return 0.0
|
||||
terms = _term_re.findall(val_str)
|
||||
if terms and len(terms) >= 2:
|
||||
coeffs = [float(t) for t in terms]
|
||||
nonzero = [c for c in coeffs if c != 0.0]
|
||||
if not nonzero:
|
||||
return 0.0
|
||||
if all(c == nonzero[0] for c in nonzero):
|
||||
return nonzero[0]
|
||||
return None
|
||||
|
||||
def feat_is_nonzero(val_str):
|
||||
v = eval_mix_expr(val_str)
|
||||
if v is None:
|
||||
return True
|
||||
return v != 0.0
|
||||
|
||||
def try_float(val_str, default=1.0):
|
||||
v = eval_mix_expr(val_str)
|
||||
return v if v is not None else default
|
||||
|
||||
def is_constant(val_str):
|
||||
return eval_mix_expr(val_str) is not None
|
||||
|
||||
warned_nonconst = set()
|
||||
|
||||
def ext_bc(name, val_str, default):
|
||||
const = is_constant(val_str)
|
||||
if not const and name not in warned_nonconst:
|
||||
warned_nonconst.add(name)
|
||||
log.warn(f'material "{material.name}": deferred ext BRDF param "{name}" has non-constant expression "{val_str}", using default {default} - per-pixel texture-driven params require deferred texturing (Phase 4)')
|
||||
c['bind_constants'].append({'name': name, 'floatValue': try_float(val_str, default), 'is_constant': const})
|
||||
|
||||
has_ext_brdf = False
|
||||
if feats.get('clearcoat', '0.0') not in ('0.0', '0', ''):
|
||||
c['bind_constants'].append({'name': 'clearcoat', 'floatValue': try_float(feats.get('clearcoat', '1.0'))})
|
||||
c['bind_constants'].append({'name': 'clearcoatRough', 'floatValue': try_float(feats.get('clearcoatRough', '0.03'), 0.03)})
|
||||
c['bind_constants'].append({'name': 'coatIOR', 'floatValue': try_float(feats.get('coatIOR', '1.5'), 1.5)})
|
||||
c['bind_constants'].append({'name': 'coatTintR', 'floatValue': try_float(feats.get('coatTintR', '1.0'), 1.0)})
|
||||
c['bind_constants'].append({'name': 'coatTintG', 'floatValue': try_float(feats.get('coatTintG', '1.0'), 1.0)})
|
||||
c['bind_constants'].append({'name': 'coatTintB', 'floatValue': try_float(feats.get('coatTintB', '1.0'), 1.0)})
|
||||
if feat_is_nonzero(feats.get('clearcoat', '0.0')):
|
||||
ext_bc('clearcoat', feats.get('clearcoat', '1.0'), 1.0)
|
||||
ext_bc('clearcoatRough', feats.get('clearcoatRough', '0.03'), 0.03)
|
||||
ext_bc('coatIOR', feats.get('coatIOR', '1.5'), 1.5)
|
||||
ext_bc('coatTintR', feats.get('coatTintR', '1.0'), 1.0)
|
||||
ext_bc('coatTintG', feats.get('coatTintG', '1.0'), 1.0)
|
||||
ext_bc('coatTintB', feats.get('coatTintB', '1.0'), 1.0)
|
||||
if '_ClearCoat' not in wrd.world_defs:
|
||||
wrd.world_defs += '_ClearCoat'
|
||||
has_ext_brdf = True
|
||||
if feats.get('sheen', '0.0') not in ('0.0', '0', ''):
|
||||
c['bind_constants'].append({'name': 'sheen', 'floatValue': try_float(feats.get('sheen', '1.0'))})
|
||||
c['bind_constants'].append({'name': 'sheenRough', 'floatValue': try_float(feats.get('sheenRough', '0.5'), 0.5)})
|
||||
c['bind_constants'].append({'name': 'sheenTintR', 'floatValue': try_float(feats.get('sheenTintR', '1.0'), 1.0)})
|
||||
c['bind_constants'].append({'name': 'sheenTintG', 'floatValue': try_float(feats.get('sheenTintG', '1.0'), 1.0)})
|
||||
c['bind_constants'].append({'name': 'sheenTintB', 'floatValue': try_float(feats.get('sheenTintB', '1.0'), 1.0)})
|
||||
if feat_is_nonzero(feats.get('sheen', '0.0')):
|
||||
ext_bc('sheen', feats.get('sheen', '1.0'), 1.0)
|
||||
ext_bc('sheenRough', feats.get('sheenRough', '0.5'), 0.5)
|
||||
ext_bc('sheenTintR', feats.get('sheenTintR', '1.0'), 1.0)
|
||||
ext_bc('sheenTintG', feats.get('sheenTintG', '1.0'), 1.0)
|
||||
ext_bc('sheenTintB', feats.get('sheenTintB', '1.0'), 1.0)
|
||||
if '_Sheen' not in wrd.world_defs:
|
||||
wrd.world_defs += '_Sheen'
|
||||
has_ext_brdf = True
|
||||
if feats.get('subsurface', '0.0') not in ('0.0', '0', '') and rpdat.rp_sss_state != 'Off' and not mat_uses_sss:
|
||||
c['bind_constants'].append({'name': 'subsurface', 'floatValue': try_float(feats.get('subsurface', '1.0'))})
|
||||
c['bind_constants'].append({'name': 'subsurfaceAnisotropy', 'floatValue': try_float(feats.get('subsurfaceAnisotropy', '0.0'), 0.0)})
|
||||
c['bind_constants'].append({'name': 'subsurfaceRadiusR', 'floatValue': try_float(feats.get('subsurfaceRadiusR', '1.0'), 1.0)})
|
||||
c['bind_constants'].append({'name': 'subsurfaceRadiusG', 'floatValue': try_float(feats.get('subsurfaceRadiusG', '0.2'), 0.2)})
|
||||
c['bind_constants'].append({'name': 'subsurfaceRadiusB', 'floatValue': try_float(feats.get('subsurfaceRadiusB', '0.1'), 0.1)})
|
||||
c['bind_constants'].append({'name': 'subsurfaceColorR', 'floatValue': try_float(feats.get('subsurfaceColorR', '0.8'), 0.8)})
|
||||
c['bind_constants'].append({'name': 'subsurfaceColorG', 'floatValue': try_float(feats.get('subsurfaceColorG', '0.8'), 0.8)})
|
||||
c['bind_constants'].append({'name': 'subsurfaceColorB', 'floatValue': try_float(feats.get('subsurfaceColorB', '0.8'), 0.8)})
|
||||
if '_Subsurface' not in wrd.world_defs:
|
||||
wrd.world_defs += '_Subsurface'
|
||||
if feat_is_nonzero(feats.get('subsurface', '0.0')) and rpdat.rp_sss_state != 'Off':
|
||||
ext_bc('subsurface', feats.get('subsurface', '1.0'), 1.0)
|
||||
ext_bc('subsurfaceAnisotropy', feats.get('subsurfaceAnisotropy', '0.0'), 0.0)
|
||||
ext_bc('subsurfaceScale', feats.get('subsurfaceScale', '0.05'), 0.05)
|
||||
ext_bc('subsurfaceRadiusR', feats.get('subsurfaceRadiusR', '1.0'), 1.0)
|
||||
ext_bc('subsurfaceRadiusG', feats.get('subsurfaceRadiusG', '0.2'), 0.2)
|
||||
ext_bc('subsurfaceRadiusB', feats.get('subsurfaceRadiusB', '0.1'), 0.1)
|
||||
ext_bc('subsurfaceColorR', feats.get('subsurfaceColorR', '0.8'), 0.8)
|
||||
ext_bc('subsurfaceColorG', feats.get('subsurfaceColorG', '0.8'), 0.8)
|
||||
ext_bc('subsurfaceColorB', feats.get('subsurfaceColorB', '0.8'), 0.8)
|
||||
if '_SSS' not in wrd.world_defs:
|
||||
wrd.world_defs += '_SSS'
|
||||
has_ext_brdf = True
|
||||
if feats.get('anisotropy', '0.0') not in ('0.0', '0', ''):
|
||||
c['bind_constants'].append({'name': 'anisotropy', 'floatValue': try_float(feats.get('anisotropy', '1.0'))})
|
||||
c['bind_constants'].append({'name': 'anisoRot', 'floatValue': try_float(feats.get('anisoRot', '0.0'), 0.0)})
|
||||
sss_used = True
|
||||
if feat_is_nonzero(feats.get('anisotropy', '0.0')):
|
||||
ext_bc('anisotropy', feats.get('anisotropy', '1.0'), 1.0)
|
||||
ext_bc('anisoRot', feats.get('anisoRot', '0.0'), 0.0)
|
||||
if '_Anisotropy' not in wrd.world_defs:
|
||||
wrd.world_defs += '_Anisotropy'
|
||||
has_ext_brdf = True
|
||||
if feats.get('transmission', '0.0') not in ('0.0', '0', ''):
|
||||
c['bind_constants'].append({'name': 'transmission', 'floatValue': try_float(feats.get('transmission', '1.0'))})
|
||||
c['bind_constants'].append({'name': 'transmissionRough', 'floatValue': try_float(feats.get('transmissionRough', '0.0'), 0.0)})
|
||||
c['bind_constants'].append({'name': 'ior', 'floatValue': try_float(feats.get('ior', '1.45'), 1.45)})
|
||||
c['bind_constants'].append({'name': 'thinWall', 'floatValue': try_float(feats.get('thinWall', '0.0'), 0.0)})
|
||||
if feat_is_nonzero(feats.get('transmission', '0.0')):
|
||||
transm_str = feats.get('transmission', '1.0')
|
||||
ext_bc('transmission', transm_str, 1.0)
|
||||
ext_bc('transmissionRough', feats.get('transmissionRough', '0.0'), 0.0)
|
||||
ior_str = feats.get('ior', '1.45')
|
||||
if not is_constant(ior_str):
|
||||
filtered = eval_filtered_expr(ior_str, transm_str)
|
||||
if filtered is not None:
|
||||
ior_str = str(filtered)
|
||||
ext_bc('ior', ior_str, 1.45)
|
||||
ext_bc('thinWall', feats.get('thinWall', '0.0'), 0.0)
|
||||
if '_Transmission' not in wrd.world_defs:
|
||||
wrd.world_defs += '_Transmission'
|
||||
has_ext_brdf = True
|
||||
@ -182,6 +250,11 @@ def parse(material: Material, mat_data, mat_users: Dict[Material, List[Object]],
|
||||
if has_ext_brdf and '_ExtBRDF' not in wrd.world_defs:
|
||||
wrd.world_defs += '_ExtBRDF'
|
||||
|
||||
if has_ext_brdf:
|
||||
ext_bc('specularTintR', feats.get('specularTintR', '1.0'), 1.0)
|
||||
ext_bc('specularTintG', feats.get('specularTintG', '1.0'), 1.0)
|
||||
ext_bc('specularTintB', feats.get('specularTintB', '1.0'), 1.0)
|
||||
|
||||
# assign materialID for extended BRDF if not already set
|
||||
# coexist with Scene.hx for last materialID in bind_constants
|
||||
if has_ext_brdf and material.lnx_material_id == 0:
|
||||
@ -191,6 +264,11 @@ def parse(material: Material, mat_data, mat_users: Dict[Material, List[Object]],
|
||||
c['bind_constants'].append({'name': 'materialID', 'intValue': ext_id})
|
||||
else:
|
||||
log.warn(f'material "{material.name}": extended BRDF material limit (15) exceeded, extended BRDF will be disabled for this material')
|
||||
has_ext_brdf = False
|
||||
|
||||
has_matid = any(bc.get('name') == 'materialID' for bc in c['bind_constants'] if isinstance(bc, dict))
|
||||
if not has_matid:
|
||||
c['bind_constants'].append({'name': 'materialID', 'intValue': 0})
|
||||
|
||||
# TODO: Mesh only material batching
|
||||
if wrd.lnx_batch_materials:
|
||||
|
||||
@ -77,6 +77,8 @@ def write(vert: shader.Shader, frag: shader.Shader):
|
||||
if is_transparent_shadows:
|
||||
frag.add_uniform('sampler2D shadowMapSpotTransparent[4]', included=True)
|
||||
frag.add_uniform('mat4 LWVPSpotArray[maxLightsCluster]', link='_biasLightWorldViewProjectionMatrixSpotArray', included=True)
|
||||
if is_shadows_atlas:
|
||||
frag.add_uniform('vec4 tileBoundsSpotArray[maxLightsCluster]', link='_tileBoundsSpotArray', included=True)
|
||||
|
||||
frag.write('for (int i = 0; i < min(numLights, maxLightsCluster); i++) {')
|
||||
frag.write('int li = int(texelFetch(clustersData, ivec2(clusterI, i + 1), 0).r * 255);')
|
||||
@ -112,13 +114,13 @@ def write(vert: shader.Shader, frag: shader.Shader):
|
||||
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(');')
|
||||
|
||||
@ -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;')
|
||||
|
||||
@ -40,34 +40,29 @@ def make(context_id):
|
||||
# Remove fragColor = ...;
|
||||
frag.main = frag.main[:frag.main.rfind('fragColor')]
|
||||
frag.write('\n')
|
||||
|
||||
wrd = bpy.data.worlds['Lnx']
|
||||
frag.write('if (opacity <= 0.0) discard;')
|
||||
|
||||
frag.write('n /= (abs(n.x) + abs(n.y) + abs(n.z));')
|
||||
frag.write('n.xy = n.z >= 0.0 ? n.xy : octahedronWrap(n.xy);')
|
||||
|
||||
is_shadeless = mat_state.emission_type == mat_state.EmissionType.SHADELESS
|
||||
if is_shadeless or '_SSS' in wrd.world_defs or '_Hair' in wrd.world_defs:
|
||||
if is_shadeless:
|
||||
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;')
|
||||
frag.write('matid = 1;')
|
||||
frag.write('basecol = emissionCol;')
|
||||
else:
|
||||
frag.write('const uint matid = 0;')
|
||||
|
||||
if rpdat.rp_renderer == 'Deferred':
|
||||
frag.write('fragColor[0] = vec4(n.xy, roughness, 1.0);')
|
||||
frag.write('vec3 finalColor = direct + indirect;')
|
||||
frag.write('fragColor[1] = vec4(finalColor * opacity, opacity);')
|
||||
frag.write('fragColor[1] = vec4(finalColor * opacity, 1.0);')
|
||||
else:
|
||||
frag.write('vec3 finalColor = direct + indirect;')
|
||||
frag.write('fragColor[0] = vec4(finalColor * opacity, opacity);')
|
||||
frag.write('fragColor[0] = vec4(finalColor * opacity, 1.0);')
|
||||
frag.write('fragColor[1] = vec4(n.xy, roughness, 1.0);')
|
||||
|
||||
frag.write('fragColor[2] = vec4(ior, 1.0 - opacity, gl_FragCoord.z, 1.0);')
|
||||
frag.write('fragColor[2] = vec4(packIOR(ior), 1.0 - opacity, gl_FragCoord.z, 1.0);')
|
||||
# frag.write('fragColor[2] = vec4(ior, 1.0 - opacity, packFloat2(basecol.r, basecol.g), basecol.b);')
|
||||
|
||||
make_finalize.make(con_refract)
|
||||
|
||||
@ -57,9 +57,6 @@ def build(material: Material, mat_users: Dict[Material, List[Object]], mat_lnxus
|
||||
# Place empty material output to keep compiler happy..
|
||||
mat_state.output_node = mat_state.nodes.new('ShaderNodeOutputMaterial')
|
||||
|
||||
# reset for each material
|
||||
mat_state.needs_sss = False
|
||||
|
||||
wrd = bpy.data.worlds['Lnx']
|
||||
rpdat = lnx.utils.get_rp()
|
||||
rpasses = mat_utils.get_rpasses(material)
|
||||
@ -133,9 +130,7 @@ def build(material: Material, mat_users: Dict[Material, List[Object]], mat_lnxus
|
||||
shader_data_path = lnx.utils.get_fp_build() + '/compiled/Shaders/' + shader_data_name + '.lnx'
|
||||
assets.add_shader_data(shader_data_path)
|
||||
|
||||
# Store SSS state in the return tuple so it's preserved per-material
|
||||
needs_sss_result = mat_state.needs_sss
|
||||
return rpasses, mat_state.data, shader_data_name, bind_constants, bind_textures, needs_sss_result
|
||||
return rpasses, mat_state.data, shader_data_name, bind_constants, bind_textures
|
||||
|
||||
|
||||
def write_shaders(rel_path: str, con: ShaderContext, rpass: str, matname: str) -> None:
|
||||
|
||||
@ -69,42 +69,44 @@ def make_gi(context_id):
|
||||
frag.add_include('std/gbuffer.glsl')
|
||||
frag.add_include('std/brdf.glsl')
|
||||
frag.add_include('std/aabb.glsl')
|
||||
frag.write_header('#define _VoxelPass')
|
||||
|
||||
rpdat = lnx.utils.get_rp()
|
||||
frag.add_uniform('layout(r32ui) uimage3D voxels')
|
||||
|
||||
frag.write('vec3 n;')
|
||||
frag.write('vec3 nCoat = vec3(0.0, 0.0, 0.0);')
|
||||
frag.write('vec3 wposition;')
|
||||
frag.write('vec3 basecol;')
|
||||
frag.write('float roughness;') #
|
||||
frag.write('float metallic;') #
|
||||
frag.write('float occlusion;') #
|
||||
frag.write('float specular;') #
|
||||
frag.write('vec3 emissionCol = vec3(0.0);')
|
||||
frag.write('vec3 specularTint = vec3(1.0);')
|
||||
frag.write('float subsurface = 0.0;')
|
||||
frag.write('vec3 subsurfaceRadius = vec3(0.0);')
|
||||
frag.write('vec3 subsurfaceColor = vec3(0.8);')
|
||||
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('vec3 emissionCol;')
|
||||
frag.write('vec3 specularTint;')
|
||||
frag.write('float subsurface;')
|
||||
frag.write('vec3 subsurfaceRadius;')
|
||||
frag.write('vec3 subsurfaceColor;')
|
||||
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;')
|
||||
blend = mat_state.material.lnx_blending
|
||||
parse_opacity = blend or mat_utils.is_transluc(mat_state.material)
|
||||
frag.write('float ior = 1.45;')
|
||||
if parse_opacity:
|
||||
frag.write('float opacity;')
|
||||
frag.write('float ior;')
|
||||
else:
|
||||
frag.write('float opacity = 1.0;')
|
||||
|
||||
@ -271,10 +273,6 @@ def make_gi(context_id):
|
||||
frag.write_attrib('vec3 vVec = normalize(eyeDir);')
|
||||
frag.write_attrib('float dotNV = max(dot(N, vVec), 0.0);')
|
||||
|
||||
if '_Brdf' in wrd.world_defs:
|
||||
frag.add_uniform('sampler2D senvmapBrdf', link='$brdf.png')
|
||||
frag.write('vec2 envBRDF = texelFetch(senvmapBrdf, ivec2(vec2(dotNV, 1.0 - roughness) * 256.0), 0).xy;')
|
||||
|
||||
if '_Irr' in wrd.world_defs:
|
||||
frag.add_include('std/shirr.glsl')
|
||||
frag.add_uniform('vec4 shirr[7]', link='_envmapIrradiance')
|
||||
@ -284,31 +282,12 @@ def make_gi(context_id):
|
||||
else:
|
||||
frag.write('vec3 envl = vec3(0.0);')
|
||||
|
||||
if '_Rad' in wrd.world_defs:
|
||||
frag.add_uniform('sampler2D senvmapRadiance', link='_envmapRadiance')
|
||||
frag.add_uniform('int envmapNumMipmaps', link='_envmapNumMipmaps')
|
||||
frag.write('vec3 reflectionWorld = reflect(-vVec, N);')
|
||||
frag.write('float lod = getMipFromRoughness(roughness, envmapNumMipmaps);')
|
||||
frag.write('vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(reflectionWorld), lod).rgb;')
|
||||
|
||||
if '_EnvLDR' in wrd.world_defs:
|
||||
frag.write('envl = pow(envl, vec3(2.2));')
|
||||
if '_Rad' in wrd.world_defs:
|
||||
frag.write('prefilteredColor = pow(prefilteredColor, vec3(2.2));')
|
||||
|
||||
frag.write('envl *= albedo;')
|
||||
|
||||
if '_Brdf' in wrd.world_defs:
|
||||
frag.write('vec3 F = f0 + (vec3(1.0) - f0) * pow(1.0 - abs(dot(N, vVec)), 5.0);')
|
||||
frag.write('envl.rgb *= 1.0 - F;')
|
||||
if '_Rad' in wrd.world_defs:
|
||||
frag.write('envl += prefilteredColor * F;')
|
||||
elif '_EnvCol' in wrd.world_defs:
|
||||
frag.add_uniform('vec3 backgroundCol', link='_backgroundCol')
|
||||
frag.write('envl += backgroundCol * F;')
|
||||
|
||||
frag.add_uniform('float envmapStrength', link='_envmapStrength')
|
||||
frag.write('envl *= envmapStrength * occlusion;')
|
||||
frag.write('envl *= envmapStrength * voxelgiEnv * occlusion;')
|
||||
|
||||
frag.add_include('std/light.glsl')
|
||||
is_shadows = '_ShadowMap' in wrd.world_defs
|
||||
@ -343,6 +322,9 @@ def make_gi(context_id):
|
||||
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},')
|
||||
@ -364,7 +346,7 @@ def make_gi(context_id):
|
||||
frag.write(', false')
|
||||
frag.write(');')
|
||||
frag.write('}') # receiveShadow
|
||||
frag.write('direct += (lambertDiffuseBRDF(albedo, sdotNL) + specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * specular) * sunCol * svisibility;')
|
||||
frag.write('direct += vec3(sdotNL) * sunCol * svisibility;')
|
||||
# sun
|
||||
|
||||
if '_SinglePoint' in wrd.world_defs:
|
||||
@ -397,13 +379,13 @@ def make_gi(context_id):
|
||||
if '_Spot' in wrd.world_defs:
|
||||
frag.write(', true, spotData.x, spotData.y, spotDir, spotData.zw, spotRight')
|
||||
if '_ClearCoat' in wrd.world_defs:
|
||||
frag.write(', clearcoat, clearcoatRough, coatIOR, coatTint')
|
||||
frag.write(', clearcoat, clearcoatRough, coatIOR, coatTint, N')
|
||||
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(');')
|
||||
@ -462,6 +444,8 @@ def make_gi(context_id):
|
||||
if is_transparent_shadows:
|
||||
frag.add_uniform('sampler2D shadowMapSpotTransparent[4]', included=True)
|
||||
frag.add_uniform('mat4 LWVPSpotArray[maxLightsCluster]', link='_biasLightWorldViewProjectionMatrixSpotArray', included=True)
|
||||
if is_shadows_atlas:
|
||||
frag.add_uniform('vec4 tileBoundsSpotArray[maxLightsCluster]', link='_tileBoundsSpotArray', included=True)
|
||||
|
||||
frag.write('for (int i = 0; i < min(numLights, maxLightsCluster); i++) {')
|
||||
frag.write('int li = int(texelFetch(clustersData, ivec2(clusterI, i + 1), 0).r * 255);')
|
||||
@ -488,13 +472,13 @@ def make_gi(context_id):
|
||||
frag.write('\t, vec2(lightsArray[li * 3].w, lightsArray[li * 3 + 1].w)') # scale
|
||||
frag.write('\t, lightsArraySpot[li * 2 + 1].xyz') # right
|
||||
if '_ClearCoat' in wrd.world_defs:
|
||||
frag.write('\t, clearcoat, clearcoatRough, coatIOR, coatTint')
|
||||
frag.write('\t, clearcoat, clearcoatRough, coatIOR, coatTint, N')
|
||||
if '_Sheen' in wrd.world_defs:
|
||||
frag.write('\t, sheen, sheenRough, sheenTint')
|
||||
if '_Anisotropy' in wrd.world_defs:
|
||||
frag.write('\t, anisotropy, anisoRot, tangent')
|
||||
if '_Subsurface' in wrd.world_defs:
|
||||
frag.write('\t, subsurface, subsurfaceColor, subsurfaceRadius, subsurfaceAnisotropy')
|
||||
if '_SSS' in wrd.world_defs:
|
||||
frag.write('\t, subsurface, subsurfaceColor, subsurfaceRadius * subsurfaceScale, subsurfaceAnisotropy')
|
||||
if '_Transmission' in wrd.world_defs:
|
||||
frag.write('\t, transmission, transmissionRough, ior, thinWall')
|
||||
frag.write(' );')
|
||||
|
||||
@ -38,6 +38,5 @@ texture_grad = False # Sample textures using textureGrad()
|
||||
con_mesh = None # Mesh context
|
||||
uses_instancing = False # Whether the current material has at least one user with instancing enabled
|
||||
emission_type = EmissionType.NO_EMISSION
|
||||
needs_sss = False
|
||||
features = {} # tracks extended BRDF features used by current material
|
||||
next_ext_mat_id = 3 # auto assigned materialID for extended BRDF
|
||||
|
||||
@ -118,6 +118,7 @@ class ParserState:
|
||||
self.out_subsurface_anisotropy: floatstr = '0.0'
|
||||
self.out_coat_ior: floatstr = '1.5'
|
||||
self.out_coat_tint: vec3str = 'vec3(1.0)'
|
||||
self.out_coat_normal: vec3str = 'vec3(0.0)'
|
||||
|
||||
def reset_outs(self):
|
||||
"""Reset the shader output values to their default values."""
|
||||
@ -148,6 +149,7 @@ class ParserState:
|
||||
self.out_subsurface_anisotropy = '0.0'
|
||||
self.out_coat_ior = '1.5'
|
||||
self.out_coat_tint = 'vec3(1.0)'
|
||||
self.out_coat_normal = 'vec3(0.0)'
|
||||
|
||||
def get_outs(self) -> Tuple:
|
||||
"""Return the shader output values as a tuple."""
|
||||
|
||||
@ -543,12 +543,12 @@ class LnxRPListItem(bpy.types.PropertyGroup):
|
||||
name="MSAA", description="Samples per pixel usable for render paths drawing directly to framebuffer", default='1')
|
||||
|
||||
lnx_voxelgi_cones: EnumProperty(
|
||||
items=[('9', '9', '9'),
|
||||
items=[('16', '16', '16'),
|
||||
('9', '9', '9'),
|
||||
('5', '5', '5'),
|
||||
('3', '3', '3'),
|
||||
('1', '1', '1'),
|
||||
],
|
||||
name="Cones", description="Number of cones to trace", default='5', update=assets.invalidate_shader_cache)
|
||||
name="Cones", description="Number of cones to trace", default='9', update=assets.invalidate_shader_cache)
|
||||
lnx_voxelgi_diff: FloatProperty(name="Diffuse", description="", default=1.0, update=assets.invalidate_shader_cache)
|
||||
lnx_voxelgi_spec: FloatProperty(name="Reflection", description="", default=1.0, update=assets.invalidate_shader_cache)
|
||||
lnx_voxelgi_refr: FloatProperty(name="Refraction", description="", default=1.0, update=assets.invalidate_shader_cache)
|
||||
@ -559,8 +559,7 @@ class LnxRPListItem(bpy.types.PropertyGroup):
|
||||
lnx_voxelgi_step: FloatProperty(name="Step", description="Step size", default=1.0, update=assets.invalidate_shader_cache)
|
||||
lnx_voxelgi_range: FloatProperty(name="Range", description="Maximum range", default=100.0, update=assets.invalidate_shader_cache)
|
||||
lnx_voxelgi_offset: FloatProperty(name="Offset", description="Multiplicative Offset for dealing with self occlusion", default=1.0, update=assets.invalidate_shader_cache)
|
||||
lnx_voxelgi_aperture: FloatProperty(name="Aperture", description="Cone aperture for shadow trace", default=0.0, update=assets.invalidate_shader_cache)
|
||||
lnx_sss_width: FloatProperty(name="Width", description="SSS blur strength", default=1.0, update=assets.invalidate_shader_cache)
|
||||
lnx_voxelgi_aperture: FloatProperty(name="Aperture", description="Cone aperture for shadow trace", default=0.26, update=assets.invalidate_shader_cache)
|
||||
lnx_water_color: FloatVectorProperty(name="Color", size=3, default=[1, 1, 1], subtype='COLOR', min=0, max=1, update=assets.invalidate_shader_cache)
|
||||
lnx_water_level: FloatProperty(name="Level", default=0.0, update=assets.invalidate_shader_cache)
|
||||
lnx_water_displace: FloatProperty(name="Displace", default=1.0, update=assets.invalidate_shader_cache)
|
||||
|
||||
@ -1646,9 +1646,6 @@ class LNX_PT_RenderPathRendererPanel(bpy.types.Panel):
|
||||
layout.prop(rpdat, 'lnx_samples_per_pixel')
|
||||
layout.prop(rpdat, 'lnx_texture_filter')
|
||||
layout.prop(rpdat, 'rp_sss_state')
|
||||
col = layout.column()
|
||||
col.enabled = rpdat.rp_sss_state != 'Off'
|
||||
col.prop(rpdat, 'lnx_sss_width')
|
||||
layout.prop(rpdat, 'lnx_rp_displacement')
|
||||
if rpdat.lnx_rp_displacement == 'Tessellation':
|
||||
layout.label(text='Mesh')
|
||||
@ -1890,7 +1887,7 @@ class LNX_PT_RenderPathVoxelsPanel(bpy.types.Panel):
|
||||
col.prop(rpdat, 'lnx_voxelgi_shadows', text='Shadows')
|
||||
col2.prop(rpdat, 'lnx_voxelgi_refract', text='Refraction')
|
||||
#col.prop(rpdat, 'lnx_voxelgi_clipmap_count')
|
||||
#col.prop(rpdat, 'lnx_voxelgi_cones')
|
||||
col.prop(rpdat, 'lnx_voxelgi_cones')
|
||||
col.prop(rpdat, 'rp_voxelgi_resolution')
|
||||
col.prop(rpdat, 'lnx_voxelgi_size')
|
||||
#col.prop(rpdat, 'rp_voxelgi_resolution_z')
|
||||
@ -1906,10 +1903,10 @@ class LNX_PT_RenderPathVoxelsPanel(bpy.types.Panel):
|
||||
col.prop(rpdat, 'lnx_voxelgi_env')
|
||||
col.prop(rpdat, 'lnx_voxelgi_occ')
|
||||
col.label(text="Ray")
|
||||
#col.prop(rpdat, 'lnx_voxelgi_offset')
|
||||
col.prop(rpdat, 'lnx_voxelgi_offset')
|
||||
col.prop(rpdat, 'lnx_voxelgi_step')
|
||||
col.prop(rpdat, 'lnx_voxelgi_range')
|
||||
#col.prop(rpdat, 'lnx_voxelgi_aperture')
|
||||
col.prop(rpdat, 'lnx_voxelgi_aperture')
|
||||
|
||||
class LNX_PT_RenderPathWorldPanel(bpy.types.Panel):
|
||||
bl_label = "World"
|
||||
|
||||
@ -665,7 +665,8 @@ class Main {
|
||||
if rpdat.rp_voxels == 'Voxel GI' or rpdat.rp_voxels == 'Voxel AO':
|
||||
f.write("""
|
||||
public static inline var voxelgiClipmapCount = """ + str(rpdat.lnx_voxelgi_clipmap_count) + """;
|
||||
public static inline var voxelgiVoxelSize = """ + str(round(rpdat.lnx_voxelgi_size * 100) / 100) + """;""")
|
||||
public static inline var voxelgiVoxelSize = """ + str(round(rpdat.lnx_voxelgi_size * 100) / 100) + """;
|
||||
public static inline var diffuseConeCount = """ + str(rpdat.lnx_voxelgi_cones) + """;""")
|
||||
|
||||
if rpdat.rp_bloom:
|
||||
follow_blender = rpdat.lnx_bloom_follow_blender if bpy.app.version < (4, 3, 0) else False
|
||||
@ -834,12 +835,12 @@ def write_compiledglsl(defs, make_variants):
|
||||
|
||||
if '_SSRefraction' in wrd.world_defs or '_VoxelRefract' in wrd.world_defs:
|
||||
f.write(f'#define GBUF_IDX_REFRACTION {idx_refraction}\n')
|
||||
idx_refraction += 1
|
||||
|
||||
idx_anisotropy = idx_refraction
|
||||
if '_Anisotropy' in wrd.world_defs:
|
||||
f.write(f'#define GBUF_IDX_3 {idx_anisotropy}\n')
|
||||
if '_ClearCoat' in wrd.world_defs:
|
||||
f.write(f'#define GBUF_IDX_COAT_NORMAL {idx_refraction}\n')
|
||||
|
||||
ext_brdf_defs = ('_ClearCoat', '_Sheen', '_Anisotropy', '_Subsurface', '_Transmission')
|
||||
ext_brdf_defs = ('_ClearCoat', '_Sheen', '_Anisotropy', '_SSS', '_Transmission')
|
||||
if any(d in wrd.world_defs for d in ext_brdf_defs):
|
||||
f.write('#ifndef _ExtBRDF\n')
|
||||
f.write('#define _ExtBRDF\n')
|
||||
@ -855,8 +856,12 @@ def write_compiledglsl(defs, make_variants):
|
||||
if state.target == 'html5' or lnx.utils.get_gapi() == 'direct3d11':
|
||||
f.write("#define _FlipY\n")
|
||||
|
||||
f.write("""const float PI = 3.1415926535;
|
||||
const float PI2 = PI * 2.0;
|
||||
f.write("""#ifndef PI
|
||||
#define PI 3.1415926535
|
||||
#endif
|
||||
#ifndef PI2
|
||||
#define PI2 6.2831853071
|
||||
#endif
|
||||
const vec2 shadowmapSize = vec2(""" + str(shadowmap_size) + """, """ + str(shadowmap_size) + """);
|
||||
const float shadowmapCubePcfSize = """ + str((round(rpdat.lnx_pcfsize * 100) / 100) / 1000) + """;
|
||||
const int shadowmapCascades = """ + str(rpdat.rp_shadowmap_cascades) + """;
|
||||
@ -1027,6 +1032,7 @@ const float compoDOFLength = """ + str(round(lens * 100) / 100) +""";
|
||||
if rpdat.rp_voxels != 'Off':
|
||||
f.write("""const ivec3 voxelgiResolution = ivec3(""" + str(rpdat.rp_voxelgi_resolution) + """, """ + str(rpdat.rp_voxelgi_resolution) + """, """ + str(rpdat.rp_voxelgi_resolution) + """);
|
||||
const int voxelgiClipmapCount = """ + str(rpdat.lnx_voxelgi_clipmap_count) + """;
|
||||
const int diffuseConeCount = """ + str(rpdat.lnx_voxelgi_cones) + """;
|
||||
const float voxelgiOcc = """ + str(round(rpdat.lnx_voxelgi_occ * 100) / 100) + """;
|
||||
const float voxelgiVoxelSize = """ + str(round(rpdat.lnx_voxelgi_size * 1000) / 1000) + """;
|
||||
const float voxelgiStep = """ + str(round(rpdat.lnx_voxelgi_step * 1000) / 1000) + """;
|
||||
@ -1042,9 +1048,6 @@ const float voxelgiDiff = """ + str(round(rpdat.lnx_voxelgi_diff * 100) / 100) +
|
||||
const float voxelgiRefl = """ + str(round(rpdat.lnx_voxelgi_spec * 100) / 100) + """;
|
||||
const float voxelgiRefr = """ + str(round(rpdat.lnx_voxelgi_refr * 100) / 100) + """;
|
||||
""")
|
||||
if rpdat.rp_sss or '_SSS' in wrd.world_defs:
|
||||
f.write(f"const float sssWidth = {rpdat.lnx_sss_width / 10.0};\n")
|
||||
|
||||
# Skinning
|
||||
if rpdat.lnx_skin == 'On':
|
||||
f.write(
|
||||
|
||||
Reference in New Issue
Block a user