forked from LeenkxTeam/LNXSDK
Repe [T3DU] and Moises Jpelaez updates
This commit is contained in:
@ -321,29 +321,18 @@ def parse_shader(node: bpy.types.Node, socket: bpy.types.NodeSocket) -> Tuple[st
|
||||
'MIX_SHADER',
|
||||
'ADD_SHADER',
|
||||
'BSDF_PRINCIPLED',
|
||||
'PRINCIPLED_BSDF',
|
||||
'BSDF_DIFFUSE',
|
||||
'DIFFUSE_BSDF',
|
||||
'BSDF_GLOSSY',
|
||||
'GLOSSY_BSDF',
|
||||
'BSDF_SHEEN',
|
||||
'SHEEN_BSDF',
|
||||
'AMBIENT_OCCLUSION',
|
||||
'BSDF_ANISOTROPIC',
|
||||
'ANISOTROPIC_BSDF',
|
||||
'EMISSION',
|
||||
'BSDF_GLASS',
|
||||
'GLASS_BSDF',
|
||||
'BSDF_REFRACTION',
|
||||
'REFRACTION_BSDF',
|
||||
'HOLDOUT',
|
||||
'SUBSURFACE_SCATTERING',
|
||||
'BSDF_TRANSLUCENT',
|
||||
'TRANSLUCENT_BSDF',
|
||||
'BSDF_TRANSPARENT',
|
||||
'TRANSPARENT_BSDF',
|
||||
'BSDF_VELVET',
|
||||
'VELVET_BSDF',
|
||||
)
|
||||
|
||||
state.reset_outs()
|
||||
@ -377,7 +366,7 @@ def parse_shader(node: bpy.types.Node, socket: bpy.types.NodeSocket) -> Tuple[st
|
||||
mat_state.emission_type = mat_state.EmissionType.SHADED
|
||||
if state.parse_opacity:
|
||||
state.out_opacity = parse_value_input(node.inputs[1])
|
||||
state.out_ior = 1.450;
|
||||
state.out_ior = 1.450
|
||||
else:
|
||||
return parse_group(node, socket)
|
||||
|
||||
@ -394,6 +383,21 @@ def parse_shader(node: bpy.types.Node, socket: bpy.types.NodeSocket) -> Tuple[st
|
||||
return state.get_outs()
|
||||
|
||||
|
||||
# Use an array of socket names for compatibility across Blender versions
|
||||
def get_vector_input(node: bpy.types.Node, socket_names: Tuple[str, ...]) -> vec3str:
|
||||
for name in socket_names:
|
||||
if name in node.inputs:
|
||||
try:
|
||||
return parse_vector_input(node.inputs[name])
|
||||
except Exception:
|
||||
log.warn(f'Failed to parse input "{name}" on node "{node.name}"')
|
||||
else:
|
||||
# FIXME: Fallback to default value if the node isn't found
|
||||
log.warn(f'Input "{name}" not found on node "{node.name}", returning default None')
|
||||
return None
|
||||
|
||||
|
||||
|
||||
def parse_displacement_input(inp):
|
||||
if inp.is_linked:
|
||||
l = inp.links[0]
|
||||
@ -504,6 +508,20 @@ def parse_vector(node: bpy.types.Node, socket: bpy.types.NodeSocket) -> str:
|
||||
return "vec3(0, 0, 0)"
|
||||
|
||||
|
||||
# Use an array of socket names for compatibility across Blender versions
|
||||
def get_value_input(node: bpy.types.Node, socket_names: Tuple[str, ...]) -> floatstr:
|
||||
for name in socket_names:
|
||||
if name in node.inputs:
|
||||
try:
|
||||
return parse_value_input(node.inputs[name])
|
||||
except Exception:
|
||||
log.warn(f'Failed to parse input "{name}" on node "{node.name}"')
|
||||
else:
|
||||
# FIXME: Fallback to default value if the node isn't found
|
||||
log.warn(f'Input "{name}" not found on node "{node.name}", returning default 1.0')
|
||||
return '1.0'
|
||||
|
||||
|
||||
def parse_normal_map_color_input(inp, strength_input=None):
|
||||
frag = state.frag
|
||||
|
||||
@ -731,7 +749,7 @@ def store_var_name(node: bpy.types.Node) -> str:
|
||||
return name + '_store'
|
||||
|
||||
|
||||
def texture_store(node, tex, tex_name, to_linear=False, tex_link=None, default_value=None, is_lnx_mat_param=None):
|
||||
def texture_store(node, tex, tex_name, to_linear=False, unpremultiply=False, tex_link=None, default_value=None, is_lnx_mat_param=None):
|
||||
curshader = state.curshader
|
||||
|
||||
tex_store = store_var_name(node)
|
||||
@ -770,6 +788,9 @@ def texture_store(node, tex, tex_name, to_linear=False, tex_link=None, default_v
|
||||
else:
|
||||
curshader.write('vec4 {0} = texture({1}, {2}.xy);'.format(tex_store, tex_name, uv_name))
|
||||
|
||||
if unpremultiply:
|
||||
curshader.write('if ({0}.a > 0.0) {0}.rgb /= {0}.a;'.format(tex_store))
|
||||
|
||||
if to_linear:
|
||||
curshader.write('{0}.rgb = pow({0}.rgb, vec3(2.2));'.format(tex_store))
|
||||
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
str_tex_proc = """
|
||||
// <https://www.shadertoy.com/view/4dS3Wd>
|
||||
// By Morgan McGuire @morgan3d, http://graphicscodex.com
|
||||
float hash_f(const float n) { return fract(sin(n) * 1e4); }
|
||||
float hash_f(const vec2 p) { return fract(1e4 * sin(17.0 * p.x + p.y * 0.1) * (0.1 + abs(sin(p.y * 13.0 + p.x)))); }
|
||||
float hash_f(const vec3 co){ return fract(sin(dot(co.xyz, vec3(12.9898,78.233,52.8265)) * 24.384) * 43758.5453); }
|
||||
// Hash functions by Dave Hoskins
|
||||
// <https://www.shadertoy.com/view/4djSRW>
|
||||
float hash_f(float p) { p = fract(p * 0.1031); p *= p + 33.33; p *= p + p; return fract(p); }
|
||||
float hash_f(vec2 p) { vec3 p3 = fract(vec3(p.xyx) * 0.1031); p3 += dot(p3, p3.yzx + 33.33); return fract((p3.x + p3.y) * p3.z); }
|
||||
float hash_f(vec3 p3) { p3 = fract(p3 * 0.1031); p3 += dot(p3, p3.zyx + 31.32); return fract((p3.x + p3.y) * p3.z); }
|
||||
|
||||
float noise(const vec3 x) {
|
||||
const vec3 step = vec3(110, 241, 171);
|
||||
@ -418,11 +418,12 @@ float tex_brick_blender_f(vec3 co,
|
||||
|
||||
|
||||
str_tex_wave = """
|
||||
float tex_wave_f(const vec3 p, const int type, const int profile, const float dist, const float detail, const float detail_scale) {
|
||||
float tex_wave_f(const vec3 p, const int type, const int profile, const float dist, const float detail, const float detail_scale, const float phase_offset) {
|
||||
float n;
|
||||
if(type == 0) n = (p.x + p.y + p.z) * 9.5;
|
||||
else n = length(p) * 13.0;
|
||||
if(dist != 0.0) n += dist * fractal_noise(p * detail_scale, detail) * 2.0 - 1.0;
|
||||
n += phase_offset;
|
||||
if(profile == 0) { return 0.5 + 0.5 * sin(n - PI); }
|
||||
else {
|
||||
n /= 2.0 * PI;
|
||||
|
||||
@ -83,37 +83,28 @@ def parse_clamp(node: bpy.types.ShaderNodeClamp, out_socket: bpy.types.NodeSocke
|
||||
|
||||
|
||||
def parse_valtorgb(node: bpy.types.ShaderNodeValToRGB, out_socket: bpy.types.NodeSocket, state: ParserState) -> Union[floatstr, vec3str]:
|
||||
# Alpha (TODO: make ColorRamp calculation vec4-based and split afterwards)
|
||||
if out_socket == node.outputs[1]:
|
||||
return '1.0'
|
||||
|
||||
input_fac: bpy.types.NodeSocket = node.inputs[0]
|
||||
alpha_out = out_socket == node.outputs[1]
|
||||
|
||||
fac: str = c.parse_value_input(input_fac) if input_fac.is_linked else c.to_vec1(input_fac.default_value)
|
||||
interp = node.color_ramp.interpolation
|
||||
elems = node.color_ramp.elements
|
||||
|
||||
|
||||
if len(elems) == 1:
|
||||
if alpha_out:
|
||||
return c.to_vec1(elems[0].color[3]) # Return alpha from the color
|
||||
else:
|
||||
return c.to_vec3(elems[0].color) # Return RGB
|
||||
|
||||
name_prefix = c.node_name(node.name).upper()
|
||||
|
||||
if alpha_out:
|
||||
cols_var = name_prefix + '_ALPHAS'
|
||||
else:
|
||||
cols_var = name_prefix + '_COLS'
|
||||
return c.to_vec3(elems[0].color)
|
||||
|
||||
# Write color array
|
||||
# The last entry is included twice so that the interpolation
|
||||
# between indices works (no out of bounds error)
|
||||
cols_var = c.node_name(node.name).upper() + '_COLS'
|
||||
|
||||
if state.current_pass == ParserPass.REGULAR:
|
||||
if alpha_out:
|
||||
cols_entries = ', '.join(f'{elem.color[3]}' for elem in elems)
|
||||
# Add last value twice to avoid out of bounds access
|
||||
cols_entries += f', {elems[len(elems) - 1].color[3]}'
|
||||
state.curshader.add_const("float", cols_var, cols_entries, array_size=len(elems) + 1)
|
||||
else:
|
||||
# Create array of RGB values for color output
|
||||
cols_entries = ', '.join(f'vec3({elem.color[0]}, {elem.color[1]}, {elem.color[2]})' for elem in elems)
|
||||
cols_entries += f', vec3({elems[len(elems) - 1].color[0]}, {elems[len(elems) - 1].color[1]}, {elems[len(elems) - 1].color[2]})'
|
||||
state.curshader.add_const("vec3", cols_var, cols_entries, array_size=len(elems) + 1)
|
||||
cols_entries = ', '.join(f'vec3({elem.color[0]}, {elem.color[1]}, {elem.color[2]})' for elem in elems)
|
||||
cols_entries += f', vec3({elems[len(elems) - 1].color[0]}, {elems[len(elems) - 1].color[1]}, {elems[len(elems) - 1].color[2]})'
|
||||
state.curshader.add_const("vec3", cols_var, cols_entries, array_size=len(elems) + 1)
|
||||
|
||||
fac_var = c.node_name(node.name) + '_fac' + state.get_parser_pass_suffix()
|
||||
state.curshader.write(f'float {fac_var} = {fac};')
|
||||
@ -131,22 +122,22 @@ def parse_valtorgb(node: bpy.types.ShaderNodeValToRGB, out_socket: bpy.types.Nod
|
||||
|
||||
# Linear interpolation
|
||||
else:
|
||||
# Write factor array - same for both color and alpha
|
||||
facs_var = name_prefix + '_FACS'
|
||||
# Write factor array
|
||||
facs_var = c.node_name(node.name).upper() + '_FACS'
|
||||
if state.current_pass == ParserPass.REGULAR:
|
||||
facs_entries = ', '.join(str(elem.position) for elem in elems)
|
||||
# Add one more entry at the rightmost position to avoid out of bounds access
|
||||
# Add one more entry at the rightmost position so that the
|
||||
# interpolation between indices works (no out of bounds error)
|
||||
facs_entries += ', 1.0'
|
||||
state.curshader.add_const("float", facs_var, facs_entries, array_size=len(elems) + 1)
|
||||
|
||||
# Calculation for interpolation position
|
||||
# Mix color
|
||||
prev_stop_fac = f'{facs_var}[{index_var}]'
|
||||
next_stop_fac = f'{facs_var}[{index_var} + 1]'
|
||||
prev_stop_col = f'{cols_var}[{index_var}]'
|
||||
next_stop_col = f'{cols_var}[{index_var} + 1]'
|
||||
rel_pos = f'({fac_var} - {prev_stop_fac}) * (1.0 / ({next_stop_fac} - {prev_stop_fac}))'
|
||||
|
||||
# Use mix function for both alpha and color outputs (mix works on floats too)
|
||||
|
||||
return f'mix({prev_stop_col}, {next_stop_col}, max({rel_pos}, 0.0))'
|
||||
|
||||
if bpy.app.version > (3, 2, 0):
|
||||
|
||||
@ -248,7 +248,7 @@ def parse_objectinfo(node: bpy.types.ShaderNodeObjectInfo, out_socket: bpy.types
|
||||
|
||||
|
||||
def parse_particleinfo(node: bpy.types.ShaderNodeParticleInfo, out_socket: bpy.types.NodeSocket, state: ParserState) -> Union[floatstr, vec3str]:
|
||||
particles_on = lnx.utils.get_rp().lnx_particles == 'On'
|
||||
particles_on = lnx.utils.get_rp().lnx_particles == 'GPU'
|
||||
|
||||
# Index
|
||||
if out_socket == node.outputs[0]:
|
||||
@ -310,27 +310,23 @@ def parse_texcoord(node: bpy.types.ShaderNodeTexCoord, out_socket: bpy.types.Nod
|
||||
return 'vec3(0.0)'
|
||||
state.con.add_elem('tex', 'short2norm')
|
||||
state.dxdy_varying_input_value = True
|
||||
|
||||
return 'vec3(texCoord.x, 1.0 - texCoord.y, 0.0)'
|
||||
elif out_socket == node.outputs[3]: # Object
|
||||
state.dxdy_varying_input_value = True
|
||||
return 'mposition'
|
||||
elif out_socket == node.outputs[4]: # Camera
|
||||
state.curshader.add_uniform('mat4 V', link='_viewMatrix')
|
||||
if not state.frag.contains('vec3 viewPosition;'):
|
||||
state.frag.write_init('vec3 viewPosition = (V * vec4(wposition, 1.0)).xyz;')
|
||||
state.dxdy_varying_input_value = True
|
||||
return 'viewPosition'
|
||||
return 'vec3(0.0)' # 'vposition'
|
||||
elif out_socket == node.outputs[5]: # Window
|
||||
# TODO: Don't use gl_FragCoord here, it uses different axes on different graphics APIs
|
||||
state.frag.add_uniform('vec2 screenSize', link='_screenSize')
|
||||
state.dxdy_varying_input_value = True
|
||||
return f'vec3(gl_FragCoord.xy / screenSize, 0.0)'
|
||||
elif out_socket == node.outputs[6]: # Reflection
|
||||
state.curshader.add_uniform('vec3 eye', link='_cameraPosition')
|
||||
if not state.frag.contains('vec3 reflectionVector;'):
|
||||
state.frag.write_init('vec3 reflectionVector = reflect(normalize(wposition - eye), normalize(n));')
|
||||
state.dxdy_varying_input_value = True
|
||||
return 'reflectionVector'
|
||||
if state.context == ParserContext.WORLD:
|
||||
state.dxdy_varying_input_value = True
|
||||
return 'n'
|
||||
return 'vec3(0.0)'
|
||||
|
||||
|
||||
def parse_uvmap(node: bpy.types.ShaderNodeUVMap, out_socket: bpy.types.NodeSocket, state: ParserState) -> vec3str:
|
||||
|
||||
@ -85,6 +85,8 @@ def parse_addshader(node: bpy.types.ShaderNodeAddShader, out_socket: NodeSocket,
|
||||
state.out_opacity = '({0} * 0.5 + {1} * 0.5)'.format(opac1, opac2)
|
||||
state.out_ior = '({0} * 0.5 + {1} * 0.5)'.format(ior1, ior2)
|
||||
|
||||
# TODO: Refactor using c.get_*_input()
|
||||
|
||||
|
||||
if bpy.app.version < (2, 92, 0):
|
||||
def parse_bsdfprincipled(node: bpy.types.ShaderNodeBsdfPrincipled, out_socket: NodeSocket, state: ParserState) -> None:
|
||||
@ -224,12 +226,6 @@ if bpy.app.version < (4, 1, 0):
|
||||
c.write_normal(node.inputs[2])
|
||||
state.out_basecol = c.parse_vector_input(node.inputs[0])
|
||||
state.out_roughness = c.parse_value_input(node.inputs[1])
|
||||
# Prevent black material when metal = 1.0 and roughness = 0.0
|
||||
try:
|
||||
if float(state.out_roughness) < 0.00101:
|
||||
state.out_roughness = '0.001'
|
||||
except ValueError:
|
||||
pass
|
||||
state.out_metallic = '1.0'
|
||||
else:
|
||||
def parse_bsdfglossy(node: bpy.types.ShaderNodeBsdfAnisotropic, out_socket: NodeSocket, state: ParserState) -> None:
|
||||
@ -237,12 +233,6 @@ else:
|
||||
c.write_normal(node.inputs[4])
|
||||
state.out_basecol = c.parse_vector_input(node.inputs[0])
|
||||
state.out_roughness = c.parse_value_input(node.inputs[1])
|
||||
# Prevent black material when metal = 1.0 and roughness = 0.0
|
||||
try:
|
||||
if float(state.out_roughness) < 0.00101:
|
||||
state.out_roughness = '0.001'
|
||||
except ValueError:
|
||||
pass
|
||||
state.out_metallic = '1.0'
|
||||
|
||||
|
||||
|
||||
@ -28,12 +28,11 @@ if lnx.is_reload(__name__):
|
||||
else:
|
||||
lnx.enable_reload(__name__)
|
||||
|
||||
|
||||
def parse_tex_brick(node: bpy.types.ShaderNodeTexBrick, out_socket: bpy.types.NodeSocket, state: ParserState) -> Union[floatstr, vec3str]:
|
||||
state.curshader.add_function(c_functions.str_tex_brick_blender)
|
||||
|
||||
if node.inputs[0].is_linked:
|
||||
co = c.parse_vector_input(node.inputs[0])
|
||||
if node.inputs['Vector'].is_linked:
|
||||
co = c.get_vector_input(node, ['Vector'])
|
||||
else:
|
||||
co = 'bposition'
|
||||
|
||||
@ -42,23 +41,23 @@ def parse_tex_brick(node: bpy.types.ShaderNodeTexBrick, out_socket: bpy.types.No
|
||||
squash_amount = node.squash
|
||||
squash_frequency = node.squash_frequency
|
||||
|
||||
col1 = c.parse_vector_input(node.inputs[1])
|
||||
col2 = c.parse_vector_input(node.inputs[2])
|
||||
col3 = c.parse_vector_input(node.inputs[3])
|
||||
scale = c.parse_value_input(node.inputs[4])
|
||||
mortar_size = c.parse_value_input(node.inputs[5])
|
||||
mortar_smooth = c.parse_value_input(node.inputs[6])
|
||||
bias = c.parse_value_input(node.inputs[7])
|
||||
brick_width = c.parse_value_input(node.inputs[8])
|
||||
row_height = c.parse_value_input(node.inputs[9])
|
||||
#res = f'tex_brick({co} * {scale}, {col1}, {col2}, {col3})'
|
||||
col1 = c.get_vector_input(node, ['Color1'])
|
||||
col2 = c.get_vector_input(node, ['Color2'])
|
||||
mortar = c.get_vector_input(node, ['Mortar'])
|
||||
scale = c.get_value_input(node, ['Scale'])
|
||||
mortar_size = c.get_value_input(node, ['Mortar Size'])
|
||||
mortar_smooth = c.get_value_input(node, ['Mortar Smooth'])
|
||||
bias = c.get_value_input(node, ['Bias'])
|
||||
brick_width = c.get_value_input(node, ['Brick Width'])
|
||||
row_height = c.get_value_input(node, ['Row Height'])
|
||||
#res = f'tex_brick({co} * {scale}, {col1}, {col2}, {mortar})'
|
||||
|
||||
# Color
|
||||
if out_socket == node.outputs[0]:
|
||||
res = f'tex_brick_blender({co}, {col1}, {col2}, {col3}, {scale}, {mortar_size}, {mortar_smooth}, {bias}, {brick_width}, {row_height}, {offset_amount}, {offset_frequency}, {squash_amount}, {squash_frequency})'
|
||||
if out_socket == node.outputs['Color']:
|
||||
res = f'tex_brick_blender({co}, {col1}, {col2}, {mortar}, {scale}, {mortar_size}, {mortar_smooth}, {bias}, {brick_width}, {row_height}, {offset_amount}, {offset_frequency}, {squash_amount}, {squash_frequency})'
|
||||
# Fac
|
||||
else:
|
||||
res = f'tex_brick_blender_f({co}, {col1}, {col2}, {col3}, {scale}, {mortar_size}, {mortar_smooth}, {bias}, {brick_width}, {row_height}, {offset_amount}, {offset_frequency}, {squash_amount}, {squash_frequency})'
|
||||
res = f'tex_brick_blender_f({co}, {col1}, {col2}, {mortar}, {scale}, {mortar_size}, {mortar_smooth}, {bias}, {brick_width}, {row_height}, {offset_amount}, {offset_frequency}, {squash_amount}, {squash_frequency})'
|
||||
|
||||
return res
|
||||
|
||||
@ -66,28 +65,28 @@ def parse_tex_brick(node: bpy.types.ShaderNodeTexBrick, out_socket: bpy.types.No
|
||||
def parse_tex_checker(node: bpy.types.ShaderNodeTexChecker, out_socket: bpy.types.NodeSocket, state: ParserState) -> Union[floatstr, vec3str]:
|
||||
state.curshader.add_function(c_functions.str_tex_checker)
|
||||
|
||||
if node.inputs[0].is_linked:
|
||||
co = c.parse_vector_input(node.inputs[0])
|
||||
if node.inputs['Vector'].is_linked:
|
||||
co = c.get_vector_input(node, ['Vector'])
|
||||
else:
|
||||
co = 'bposition'
|
||||
|
||||
scale = c.get_value_input(node, ['Scale'])
|
||||
|
||||
# Color
|
||||
if out_socket == node.outputs[0]:
|
||||
col1 = c.parse_vector_input(node.inputs[1])
|
||||
col2 = c.parse_vector_input(node.inputs[2])
|
||||
scale = c.parse_value_input(node.inputs[3])
|
||||
if out_socket == node.outputs['Color']:
|
||||
col1 = c.get_vector_input(node, ['Color1'])
|
||||
col2 = c.get_vector_input(node, ['Color2'])
|
||||
res = f'tex_checker({co}, {col1}, {col2}, {scale})'
|
||||
# Fac
|
||||
else:
|
||||
scale = c.parse_value_input(node.inputs[3])
|
||||
res = 'tex_checker_f({0}, {1})'.format(co, scale)
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def parse_tex_gradient(node: bpy.types.ShaderNodeTexGradient, out_socket: bpy.types.NodeSocket, state: ParserState) -> Union[floatstr, vec3str]:
|
||||
if node.inputs[0].is_linked:
|
||||
co = c.parse_vector_input(node.inputs[0])
|
||||
if node.inputs['Vector'].is_linked:
|
||||
co = c.get_vector_input(node, ['Vector'])
|
||||
else:
|
||||
co = 'bposition'
|
||||
|
||||
@ -108,7 +107,7 @@ def parse_tex_gradient(node: bpy.types.ShaderNodeTexGradient, out_socket: bpy.ty
|
||||
f = f'max(1.0 - sqrt({co}.x * {co}.x + {co}.y * {co}.y + {co}.z * {co}.z), 0.0)'
|
||||
|
||||
# Color
|
||||
if out_socket == node.outputs[0]:
|
||||
if out_socket == node.outputs['Color']:
|
||||
res = f'vec3(clamp({f}, 0.0, 1.0))'
|
||||
# Fac
|
||||
else:
|
||||
@ -119,7 +118,7 @@ def parse_tex_gradient(node: bpy.types.ShaderNodeTexGradient, out_socket: bpy.ty
|
||||
|
||||
def parse_tex_image(node: bpy.types.ShaderNodeTexImage, out_socket: bpy.types.NodeSocket, state: ParserState) -> Union[floatstr, vec3str]:
|
||||
# Color or Alpha output
|
||||
use_color_out = out_socket == node.outputs[0]
|
||||
use_color_out = out_socket == node.outputs['Color']
|
||||
|
||||
if state.context == ParserContext.OBJECT:
|
||||
tex_store = c.store_var_name(node)
|
||||
@ -147,11 +146,12 @@ def parse_tex_image(node: bpy.types.ShaderNodeTexImage, out_socket: bpy.types.No
|
||||
state.curshader.write_textures += 1
|
||||
if node.lnx_material_param and tex['file'] is not None:
|
||||
tex_default_file = tex['file']
|
||||
unpremultiply = node.image is not None and node.image.alpha_mode != 'CHANNEL_PACKED'
|
||||
if use_color_out:
|
||||
to_linear = node.image is not None and node.image.colorspace_settings.name == 'sRGB'
|
||||
res = f'{c.texture_store(node, tex, tex_name, to_linear, tex_link=tex_link, default_value=tex_default_file, is_lnx_mat_param=is_lnx_mat_param)}.rgb'
|
||||
res = f'{c.texture_store(node, tex, tex_name, to_linear, unpremultiply, tex_link=tex_link, default_value=tex_default_file, is_lnx_mat_param=is_lnx_mat_param)}.rgb'
|
||||
else:
|
||||
res = f'{c.texture_store(node, tex, tex_name, tex_link=tex_link, default_value=tex_default_file, is_lnx_mat_param=is_lnx_mat_param)}.a'
|
||||
res = f'{c.texture_store(node, tex, tex_name, unpremultiply, tex_link=tex_link, default_value=tex_default_file, is_lnx_mat_param=is_lnx_mat_param)}.a'
|
||||
state.curshader.write_textures -= 1
|
||||
return res
|
||||
|
||||
@ -162,8 +162,8 @@ def parse_tex_image(node: bpy.types.ShaderNodeTexImage, out_socket: bpy.types.No
|
||||
'file': ''
|
||||
}
|
||||
if use_color_out:
|
||||
return '{0}.rgb'.format(c.texture_store(node, tex, tex_name, to_linear=False, tex_link=tex_link, is_lnx_mat_param=is_lnx_mat_param))
|
||||
return '{0}.a'.format(c.texture_store(node, tex, tex_name, to_linear=True, tex_link=tex_link, is_lnx_mat_param=is_lnx_mat_param))
|
||||
return '{0}.rgb'.format(c.texture_store(node, tex, tex_name, to_linear=False, unpremultiply=False, tex_link=tex_link, is_lnx_mat_param=is_lnx_mat_param))
|
||||
return '{0}.a'.format(c.texture_store(node, tex, tex_name, to_linear=True, unpremultiply=False, tex_link=tex_link, is_lnx_mat_param=is_lnx_mat_param))
|
||||
|
||||
# Pink color for missing texture
|
||||
else:
|
||||
@ -240,15 +240,15 @@ def parse_tex_image(node: bpy.types.ShaderNodeTexImage, out_socket: bpy.types.No
|
||||
def parse_tex_magic(node: bpy.types.ShaderNodeTexMagic, out_socket: bpy.types.NodeSocket, state: ParserState) -> Union[floatstr, vec3str]:
|
||||
state.curshader.add_function(c_functions.str_tex_magic)
|
||||
|
||||
if node.inputs[0].is_linked:
|
||||
co = c.parse_vector_input(node.inputs[0])
|
||||
if node.inputs['Vector'].is_linked:
|
||||
co = c.get_vector_input(node, ['Vector'])
|
||||
else:
|
||||
co = 'bposition'
|
||||
|
||||
scale = c.parse_value_input(node.inputs[1])
|
||||
scale = c.get_value_input(node, ['Scale'])
|
||||
|
||||
# Color
|
||||
if out_socket == node.outputs[0]:
|
||||
if out_socket == node.outputs['Color']:
|
||||
res = f'tex_magic({co} * {scale} * 4.0)'
|
||||
# Fac
|
||||
else:
|
||||
@ -260,17 +260,17 @@ if bpy.app.version < (4, 1, 0):
|
||||
def parse_tex_musgrave(node: bpy.types.ShaderNodeTexMusgrave, out_socket: bpy.types.NodeSocket, state: ParserState) -> Union[floatstr, vec3str]:
|
||||
state.curshader.add_function(c_functions.str_tex_musgrave)
|
||||
|
||||
if node.inputs[0].is_linked:
|
||||
co = c.parse_vector_input(node.inputs[0])
|
||||
if node.inputs['Vector'].is_linked:
|
||||
co = c.get_vector_input(node, ['Vector'])
|
||||
else:
|
||||
co = 'bposition'
|
||||
|
||||
scale = c.parse_value_input(node.inputs['Scale'])
|
||||
detail = c.parse_value_input(node.inputs[3])
|
||||
distortion = c.parse_value_input(node.inputs[4])
|
||||
|
||||
res = f'tex_musgrave_f({co} * {scale} * 0.5, {detail}, {distortion})'
|
||||
|
||||
scale = c.get_value_input(node, ['Scale'])
|
||||
detail = c.get_value_input(node, ['Detail'])
|
||||
dimension = c.get_value_input(node, ['Dimension'])
|
||||
|
||||
res = f'tex_musgrave_f({co} * {scale} * 0.5, {detail}, {dimension})' # FIXME: a `distortion` is applied instead of a `dimension`
|
||||
|
||||
return res
|
||||
|
||||
|
||||
@ -280,28 +280,30 @@ def parse_tex_noise(node: bpy.types.ShaderNodeTexNoise, out_socket: bpy.types.No
|
||||
c.assets_add(os.path.join(lnx.utils.get_sdk_path(), 'leenkx', 'Assets', 'noise256.png'))
|
||||
c.assets_add_embedded_data('noise256.png')
|
||||
state.curshader.add_uniform('sampler2D snoise256', link='$noise256.png')
|
||||
if node.inputs[0].is_linked:
|
||||
co = c.parse_vector_input(node.inputs[0])
|
||||
if node.inputs['Vector'].is_linked:
|
||||
co = c.get_vector_input(node, ['Vector'])
|
||||
else:
|
||||
co = 'bposition'
|
||||
scale = c.parse_value_input(node.inputs[2])
|
||||
detail = c.parse_value_input(node.inputs[3])
|
||||
roughness = c.parse_value_input(node.inputs[4])
|
||||
distortion = c.parse_value_input(node.inputs[5])
|
||||
scale = c.get_value_input(node, ['Scale'])
|
||||
detail = c.get_value_input(node, ['Detail'])
|
||||
roughness = c.get_value_input(node, ['Roughness'])
|
||||
distortion = c.get_value_input(node, ['Distortion'])
|
||||
if bpy.app.version >= (4, 1, 0):
|
||||
if node.noise_type == "FBM":
|
||||
state.curshader.add_function(c_functions.str_tex_musgrave)
|
||||
if out_socket == node.outputs[1]:
|
||||
if out_socket == node.outputs['Color']:
|
||||
res = 'vec3(tex_musgrave_f({0} * {1}, {2}, {3}), tex_musgrave_f({0} * {1} + 120.0, {2}, {3}), tex_musgrave_f({0} * {1} + 168.0, {2}, {3}))'.format(co, scale, detail, distortion)
|
||||
else:
|
||||
res = f'tex_musgrave_f({co} * {scale} * 1.0, {detail}, {distortion})'
|
||||
else:
|
||||
if out_socket == node.outputs[1]:
|
||||
if out_socket == node.outputs['Color']:
|
||||
res = 'vec3(tex_noise({0} * {1},{2},{3}), tex_noise({0} * {1} + 120.0,{2},{3}), tex_noise({0} * {1} + 168.0,{2},{3}))'.format(co, scale, detail, distortion)
|
||||
else:
|
||||
res = 'tex_noise({0} * {1},{2},{3})'.format(co, scale, detail, distortion)
|
||||
if node.normalize:
|
||||
res = f'(1.0 - ({res}))'
|
||||
else:
|
||||
if out_socket == node.outputs[1]:
|
||||
if out_socket == node.outputs['Color']:
|
||||
res = 'vec3(tex_noise({0} * {1},{2},{3}), tex_noise({0} * {1} + 120.0,{2},{3}), tex_noise({0} * {1} + 168.0,{2},{3}))'.format(co, scale, detail, distortion)
|
||||
else:
|
||||
res = 'tex_noise({0} * {1},{2},{3})'.format(co, scale, detail, distortion)
|
||||
@ -311,7 +313,7 @@ if bpy.app.version < (5, 0, 0):
|
||||
def parse_tex_pointdensity(node: bpy.types.ShaderNodeTexPointDensity, out_socket: bpy.types.NodeSocket, state: ParserState) -> Union[floatstr, vec3str]:
|
||||
# Pass through
|
||||
# Color
|
||||
if out_socket == node.outputs[0]:
|
||||
if out_socket == node.outputs['Color']:
|
||||
return c.to_vec3([0.0, 0.0, 0.0])
|
||||
# Density
|
||||
else:
|
||||
@ -546,21 +548,24 @@ def parse_tex_voronoi(node: bpy.types.ShaderNodeTexVoronoi, out_socket: bpy.type
|
||||
m = 2
|
||||
elif node.distance == 'MINKOWSKI':
|
||||
m = 3
|
||||
# TODO: Add node.distance == 'MANHATHAN'
|
||||
# Add node.feature
|
||||
# Add node.voronoi_dimensions
|
||||
|
||||
c.write_procedurals()
|
||||
state.curshader.add_function(c_functions.str_tex_voronoi)
|
||||
|
||||
if node.inputs[0].is_linked:
|
||||
co = c.parse_vector_input(node.inputs[0])
|
||||
if node.inputs['Vector'].is_linked:
|
||||
co = c.get_vector_input(node, ['Vector'])
|
||||
else:
|
||||
co = 'bposition'
|
||||
|
||||
scale = c.parse_value_input(node.inputs[2])
|
||||
exp = c.parse_value_input(node.inputs[4])
|
||||
randomness = c.parse_value_input(node.inputs[5])
|
||||
scale = c.get_value_input(node, ['Scale'])
|
||||
exp = c.get_value_input(node, ['Exponent'])
|
||||
randomness = c.get_value_input(node, ['Randomness'])
|
||||
|
||||
# Color or Position
|
||||
if out_socket == node.outputs[1] or out_socket == node.outputs[2]:
|
||||
if out_socket == node.outputs['Color'] or out_socket == node.outputs['Position']:
|
||||
res = 'tex_voronoi({0}, {1}, {2}, {3}, {4}, {5})'.format(co, randomness, m, outp, scale, exp)
|
||||
# Distance
|
||||
else:
|
||||
@ -572,14 +577,16 @@ def parse_tex_voronoi(node: bpy.types.ShaderNodeTexVoronoi, out_socket: bpy.type
|
||||
def parse_tex_wave(node: bpy.types.ShaderNodeTexWave, out_socket: bpy.types.NodeSocket, state: ParserState) -> Union[floatstr, vec3str]:
|
||||
c.write_procedurals()
|
||||
state.curshader.add_function(c_functions.str_tex_wave)
|
||||
if node.inputs[0].is_linked:
|
||||
co = c.parse_vector_input(node.inputs[0])
|
||||
if node.inputs['Vector'].is_linked:
|
||||
co = c.get_vector_input(node, ['Vector'])
|
||||
else:
|
||||
co = 'bposition'
|
||||
scale = c.parse_value_input(node.inputs[1])
|
||||
distortion = c.parse_value_input(node.inputs[2])
|
||||
detail = c.parse_value_input(node.inputs[3])
|
||||
detail_scale = c.parse_value_input(node.inputs[4])
|
||||
scale = c.get_value_input(node, ['Scale'])
|
||||
distortion = c.get_value_input(node, ['Distortion'])
|
||||
detail = c.get_value_input(node, ['Detail'])
|
||||
detail_scale = c.get_value_input(node, ['Detail Scale'])
|
||||
phase_offset = c.get_value_input(node, ['Phase Offset'])
|
||||
|
||||
if node.wave_profile == 'SIN':
|
||||
wave_profile = 0
|
||||
else:
|
||||
@ -590,10 +597,10 @@ def parse_tex_wave(node: bpy.types.ShaderNodeTexWave, out_socket: bpy.types.Node
|
||||
wave_type = 1
|
||||
|
||||
# Color
|
||||
if out_socket == node.outputs[0]:
|
||||
res = 'vec3(tex_wave_f({0} * {1},{2},{3},{4},{5},{6}))'.format(co, scale, wave_type, wave_profile, distortion, detail, detail_scale)
|
||||
if out_socket == node.outputs['Color']:
|
||||
res = 'vec3(tex_wave_f({0} * {1},{2},{3},{4},{5},{6},{7}))'.format(co, scale, wave_type, wave_profile, distortion, detail, detail_scale, phase_offset)
|
||||
# Fac
|
||||
else:
|
||||
res = 'tex_wave_f({0} * {1},{2},{3},{4},{5},{6})'.format(co, scale, wave_type, wave_profile, distortion, detail, detail_scale)
|
||||
res = 'tex_wave_f({0} * {1},{2},{3},{4},{5},{6},{7})'.format(co, scale, wave_type, wave_profile, distortion, detail, detail_scale, phase_offset)
|
||||
|
||||
return res
|
||||
|
||||
@ -25,8 +25,8 @@ else:
|
||||
|
||||
|
||||
def parse_curvevec(node: bpy.types.ShaderNodeVectorCurve, out_socket: bpy.types.NodeSocket, state: ParserState) -> vec3str:
|
||||
fac = c.parse_value_input(node.inputs[0])
|
||||
vec = c.parse_vector_input(node.inputs[1])
|
||||
fac = c.get_value_input(node, ['Fac'])
|
||||
vec = c.get_vector_input(node, ['Vector'])
|
||||
curves = node.mapping.curves
|
||||
name = c.node_name(node.name)
|
||||
# mapping.curves[0].points[0].handle_type # bezier curve
|
||||
@ -42,19 +42,17 @@ def parse_bump(node: bpy.types.ShaderNodeBump, out_socket: bpy.types.NodeSocket,
|
||||
return 'vec3(0.0)'
|
||||
|
||||
# Interpolation strength
|
||||
strength = c.parse_value_input(node.inputs[0])
|
||||
# Height multiplier
|
||||
# distance = c.parse_value_input(node.inputs[1])
|
||||
height = c.parse_value_input(node.inputs[2])
|
||||
strength = c.get_value_input(node, ['Strength'])
|
||||
# distance = c.get_value_input(node, ['Distance'])
|
||||
height = c.get_value_input(node, ['Height'])
|
||||
# normal = c.get_vector_input(node, ['Normal'])
|
||||
|
||||
state.current_pass = ParserPass.DX_SCREEN_SPACE
|
||||
height_dx = c.parse_value_input(node.inputs[2])
|
||||
height_dx = c.get_value_input(node, ['Height'])
|
||||
state.current_pass = ParserPass.DY_SCREEN_SPACE
|
||||
height_dy = c.parse_value_input(node.inputs[2])
|
||||
height_dy = c.get_value_input(node, ['Height'])
|
||||
state.current_pass = ParserPass.REGULAR
|
||||
|
||||
# nor = c.parse_vector_input(node.inputs[3])
|
||||
|
||||
if height_dx != height or height_dy != height:
|
||||
tangent = f'{c.dfdx_fine("wposition")} + n * ({height_dx} - {height})'
|
||||
bitangent = f'{c.dfdy_fine("wposition")} + n * ({height_dy} - {height})'
|
||||
@ -79,11 +77,12 @@ def parse_bump(node: bpy.types.ShaderNodeBump, out_socket: bpy.types.NodeSocket,
|
||||
|
||||
|
||||
def parse_mapping(node: bpy.types.ShaderNodeMapping, out_socket: bpy.types.NodeSocket, state: ParserState) -> vec3str:
|
||||
# TODO: Add support for "Normal" type
|
||||
# Only "Point", "Texture" and "Vector" types supported for now..
|
||||
# More information about the order of operations for this node:
|
||||
# https://docs.blender.org/manual/en/latest/render/shader_nodes/vector/mapping.html#properties
|
||||
|
||||
input_vector: bpy.types.NodeSocket = node.inputs[0]
|
||||
input_vector: bpy.types.NodeSocket = node.inputs['Vector']
|
||||
input_location: bpy.types.NodeSocket = node.inputs['Location']
|
||||
input_rotation: bpy.types.NodeSocket = node.inputs['Rotation']
|
||||
input_scale: bpy.types.NodeSocket = node.inputs['Scale']
|
||||
@ -145,44 +144,48 @@ def parse_normal(node: bpy.types.ShaderNodeNormal, out_socket: bpy.types.NodeSoc
|
||||
return nor1
|
||||
|
||||
elif out_socket == node.outputs['Dot']:
|
||||
nor2 = c.parse_vector_input(node.inputs["Normal"])
|
||||
nor2 = c.get_vector_input(node, ["Normal"])
|
||||
return f'dot({nor1}, {nor2})'
|
||||
|
||||
|
||||
def parse_normalmap(node: bpy.types.ShaderNodeNormalMap, out_socket: bpy.types.NodeSocket, state: ParserState) -> vec3str:
|
||||
if state.curshader == state.tese:
|
||||
return c.parse_vector_input(node.inputs[1])
|
||||
return c.get_vector_input(node, ["Normal"])
|
||||
else:
|
||||
# TODO:
|
||||
# space = node.space
|
||||
# map = node.uv_map
|
||||
# Color
|
||||
c.parse_normal_map_color_input(node.inputs[1], node.inputs[0])
|
||||
c.parse_normal_map_color_input(node.inputs['Color'], node.inputs['Strength'])
|
||||
return 'n'
|
||||
|
||||
|
||||
def parse_vectortransform(node: bpy.types.ShaderNodeVectorTransform, out_socket: bpy.types.NodeSocket, state: ParserState) -> vec3str:
|
||||
# type = node.vector_type
|
||||
# TODO:
|
||||
# vector_type = node.vector_type
|
||||
# conv_from = node.convert_from
|
||||
# conv_to = node.convert_to
|
||||
# Pass through
|
||||
return c.parse_vector_input(node.inputs[0])
|
||||
return c.get_vector_input(node, ['Vector'])
|
||||
|
||||
|
||||
def parse_displacement(node: bpy.types.ShaderNodeDisplacement, out_socket: bpy.types.NodeSocket, state: ParserState) -> vec3str:
|
||||
height = c.parse_value_input(node.inputs[0])
|
||||
midlevel = c.parse_value_input(node.inputs[1])
|
||||
scale = c.parse_value_input(node.inputs[2])
|
||||
nor = c.parse_vector_input(node.inputs[3])
|
||||
# TODO:
|
||||
# space = node.space
|
||||
height = c.get_value_input(node, ['Height'])
|
||||
midlevel = c.get_value_input(node, ['Midlevel'])
|
||||
scale = c.get_value_input(node, ['Scale'])
|
||||
nor = c.get_vector_input(node, ['Normal'])
|
||||
return f'(vec3({height}) * {scale})'
|
||||
|
||||
def parse_vectorrotate(node: bpy.types.ShaderNodeVectorRotate, out_socket: bpy.types.NodeSocket, state: ParserState) -> vec3str:
|
||||
|
||||
type = node.rotation_type
|
||||
input_vector: bpy.types.NodeSocket = c.parse_vector_input(node.inputs[0])
|
||||
input_center: bpy.types.NodeSocket = c.parse_vector_input(node.inputs[1])
|
||||
input_axis: bpy.types.NodeSocket = c.parse_vector_input(node.inputs[2])
|
||||
input_angle: bpy.types.NodeSocket = c.parse_value_input(node.inputs[3])
|
||||
input_rotation: bpy.types.NodeSocket = c.parse_vector_input(node.inputs[4])
|
||||
input_vector: bpy.types.NodeSocket = c.get_vector_input(node, ['Vector'])
|
||||
input_center: bpy.types.NodeSocket = c.get_vector_input(node, ['Center'])
|
||||
input_axis: bpy.types.NodeSocket = c.get_vector_input(node, ['Axis'])
|
||||
input_angle: bpy.types.NodeSocket = c.get_value_input(node, ['Angle'])
|
||||
input_rotation: bpy.types.NodeSocket = c.get_vector_input(node, ['Rotation'])
|
||||
|
||||
if node.invert:
|
||||
input_invert = "0"
|
||||
|
||||
@ -1,100 +1,212 @@
|
||||
from typing import Optional
|
||||
|
||||
|
||||
|
||||
import lnx.material.cycles as cycles
|
||||
|
||||
import lnx.material.mat_state as mat_state
|
||||
|
||||
import lnx.material.make_skin as make_skin
|
||||
|
||||
import lnx.material.make_particle as make_particle
|
||||
|
||||
import lnx.material.make_inst as make_inst
|
||||
|
||||
import lnx.material.make_tess as make_tess
|
||||
|
||||
import lnx.material.make_morph_target as make_morph_target
|
||||
|
||||
from lnx.material.shader import Shader, ShaderContext
|
||||
|
||||
import lnx.utils
|
||||
|
||||
|
||||
|
||||
if lnx.is_reload(__name__):
|
||||
|
||||
cycles = lnx.reload_module(cycles)
|
||||
|
||||
mat_state = lnx.reload_module(mat_state)
|
||||
|
||||
make_skin = lnx.reload_module(make_skin)
|
||||
|
||||
make_particle = lnx.reload_module(make_particle)
|
||||
|
||||
make_inst = lnx.reload_module(make_inst)
|
||||
|
||||
make_tess = lnx.reload_module(make_tess)
|
||||
|
||||
make_morph_target = lnx.reload_module(make_morph_target)
|
||||
|
||||
lnx.material.shader = lnx.reload_module(lnx.material.shader)
|
||||
|
||||
from lnx.material.shader import Shader, ShaderContext
|
||||
|
||||
lnx.utils = lnx.reload_module(lnx.utils)
|
||||
|
||||
else:
|
||||
|
||||
lnx.enable_reload(__name__)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def write_vertpos(vert):
|
||||
|
||||
billboard = mat_state.material.lnx_billboard
|
||||
|
||||
particle = mat_state.material.lnx_particle_flag
|
||||
|
||||
# Particles
|
||||
|
||||
if particle:
|
||||
if lnx.utils.get_rp().lnx_particles == 'On':
|
||||
|
||||
if lnx.utils.get_rp().lnx_particles == 'GPU':
|
||||
|
||||
make_particle.write(vert, particle_info=cycles.particle_info)
|
||||
|
||||
# Billboards
|
||||
|
||||
if billboard == 'spherical':
|
||||
|
||||
vert.add_uniform('mat4 WV', '_worldViewMatrix')
|
||||
|
||||
vert.add_uniform('mat4 P', '_projectionMatrix')
|
||||
|
||||
vert.write('gl_Position = P * (WV * vec4(0.0, 0.0, spos.z, 1.0) + vec4(spos.x, spos.y, 0.0, 0.0));')
|
||||
|
||||
else:
|
||||
|
||||
vert.add_uniform('mat4 WVP', '_worldViewProjectionMatrix')
|
||||
|
||||
vert.write('gl_Position = WVP * spos;')
|
||||
|
||||
else:
|
||||
|
||||
# Billboards
|
||||
|
||||
if billboard == 'spherical':
|
||||
|
||||
vert.add_uniform('mat4 WVP', '_worldViewProjectionMatrixSphere')
|
||||
|
||||
elif billboard == 'cylindrical':
|
||||
|
||||
vert.add_uniform('mat4 WVP', '_worldViewProjectionMatrixCylinder')
|
||||
|
||||
else: # off
|
||||
|
||||
vert.add_uniform('mat4 WVP', '_worldViewProjectionMatrix')
|
||||
|
||||
vert.write('gl_Position = WVP * spos;')
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def write_norpos(con_mesh: ShaderContext, vert: Shader, declare=False, write_nor=True):
|
||||
|
||||
is_bone = con_mesh.is_elem('bone')
|
||||
|
||||
is_morph = con_mesh.is_elem('morph')
|
||||
|
||||
if is_morph:
|
||||
|
||||
make_morph_target.morph_pos(vert)
|
||||
|
||||
if is_bone:
|
||||
|
||||
make_skin.skin_pos(vert)
|
||||
|
||||
if write_nor:
|
||||
|
||||
prep = 'vec3 ' if declare else ''
|
||||
|
||||
if is_morph:
|
||||
|
||||
make_morph_target.morph_nor(vert, is_bone, prep)
|
||||
|
||||
if is_bone:
|
||||
|
||||
make_skin.skin_nor(vert, is_morph, prep)
|
||||
|
||||
if not is_morph and not is_bone:
|
||||
|
||||
vert.write_attrib(prep + 'wnormal = normalize(N * vec3(nor.xy, pos.w));')
|
||||
|
||||
if con_mesh.is_elem('ipos'):
|
||||
|
||||
make_inst.inst_pos(con_mesh, vert)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def write_tex_coords(con_mesh: ShaderContext, vert: Shader, frag: Shader, tese: Optional[Shader]):
|
||||
|
||||
rpdat = lnx.utils.get_rp()
|
||||
|
||||
|
||||
|
||||
if con_mesh.is_elem('tex'):
|
||||
|
||||
vert.add_out('vec2 texCoord')
|
||||
|
||||
vert.add_uniform('float texUnpack', link='_texUnpack')
|
||||
|
||||
if mat_state.material.lnx_tilesheet_flag:
|
||||
|
||||
if mat_state.material.lnx_particle_flag and rpdat.lnx_particles == 'On':
|
||||
|
||||
make_particle.write_tilesheet(vert)
|
||||
|
||||
else:
|
||||
|
||||
vert.add_uniform('vec2 tilesheetOffset', '_tilesheetOffset')
|
||||
vert.write_attrib('texCoord = tex * texUnpack + tilesheetOffset;')
|
||||
|
||||
vert.add_uniform('vec2 tilesheetFlip', '_tilesheetFlip')
|
||||
|
||||
vert.add_uniform('vec2 tilesheetTiles', '_tilesheetTiles')
|
||||
|
||||
vert.write_attrib('vec2 tileSize = vec2(1.0 / tilesheetTiles.x, 1.0 / tilesheetTiles.y);')
|
||||
|
||||
vert.write_attrib('vec2 tileUV = tex * texUnpack;')
|
||||
|
||||
vert.write_attrib('tileUV.x = mix(tileUV.x, tileSize.x - tileUV.x, tilesheetFlip.x);')
|
||||
|
||||
vert.write_attrib('tileUV.y = mix(tileUV.y, tileSize.y - tileUV.y, tilesheetFlip.y);')
|
||||
|
||||
vert.write_attrib('texCoord = tileUV + tilesheetOffset;')
|
||||
|
||||
else:
|
||||
|
||||
vert.write_attrib('texCoord = tex * texUnpack;')
|
||||
|
||||
|
||||
|
||||
if tese is not None:
|
||||
|
||||
tese.write_pre = True
|
||||
|
||||
make_tess.interpolate(tese, 'texCoord', 2, declare_out=frag.contains('texCoord'))
|
||||
|
||||
tese.write_pre = False
|
||||
|
||||
|
||||
|
||||
if con_mesh.is_elem('tex1'):
|
||||
|
||||
vert.add_out('vec2 texCoord1')
|
||||
|
||||
vert.add_uniform('float texUnpack', link='_texUnpack')
|
||||
|
||||
vert.write_attrib('texCoord1 = tex1 * texUnpack;')
|
||||
|
||||
if tese is not None:
|
||||
|
||||
tese.write_pre = True
|
||||
|
||||
make_tess.interpolate(tese, 'texCoord1', 2, declare_out=frag.contains('texCoord1'))
|
||||
|
||||
tese.write_pre = False
|
||||
|
||||
|
||||
@ -112,7 +112,7 @@ def make(context_id, rpasses, shadowmap=False, shadowmap_transparent=False):
|
||||
make_inst.inst_pos(con_depth, vert)
|
||||
|
||||
rpdat = lnx.utils.get_rp()
|
||||
if mat_state.material.lnx_particle_flag and rpdat.lnx_particles == 'On':
|
||||
if mat_state.material.lnx_particle_flag and rpdat.lnx_particles == 'GPU':
|
||||
make_particle.write(vert, shadowmap=shadowmap)
|
||||
|
||||
if is_disp:
|
||||
|
||||
@ -58,6 +58,7 @@ def make(context_id, rpasses):
|
||||
con['alpha_blend_destination'] = mat.lnx_blending_destination_alpha
|
||||
con['alpha_blend_operation'] = mat.lnx_blending_operation_alpha
|
||||
con['depth_write'] = False
|
||||
con['compare_mode'] = mat.lnx_compare_mode
|
||||
elif particle:
|
||||
pass
|
||||
# Depth prepass was performed, exclude mat with depth read that
|
||||
@ -500,7 +501,13 @@ def make_forward_solid(con_mesh):
|
||||
vert.add_uniform('float texUnpack', link='_texUnpack')
|
||||
if mat_state.material.lnx_tilesheet_flag:
|
||||
vert.add_uniform('vec2 tilesheetOffset', '_tilesheetOffset')
|
||||
vert.write('texCoord = tex * texUnpack + tilesheetOffset;')
|
||||
vert.add_uniform('vec2 tilesheetFlip', '_tilesheetFlip')
|
||||
vert.add_uniform('vec2 tilesheetTiles', '_tilesheetTiles')
|
||||
vert.write('vec2 tileSize = vec2(1.0 / tilesheetTiles.x, 1.0 / tilesheetTiles.y);')
|
||||
vert.write('vec2 tileUV = tex * texUnpack;')
|
||||
vert.write('tileUV.x = mix(tileUV.x, tileSize.x - tileUV.x, tilesheetFlip.x);')
|
||||
vert.write('tileUV.y = mix(tileUV.y, tileSize.y - tileUV.y, tilesheetFlip.y);')
|
||||
vert.write('texCoord = tileUV + tilesheetOffset;')
|
||||
else:
|
||||
vert.write('texCoord = tex * texUnpack;')
|
||||
|
||||
@ -571,7 +578,7 @@ def make_forward(con_mesh):
|
||||
frag.write('fragColor[0].rgb = tonemapFilmic(fragColor[0].rgb);')
|
||||
|
||||
# Particle opacity
|
||||
if mat_state.material.lnx_particle_flag and lnx.utils.get_rp().lnx_particles == 'On' and mat_state.material.lnx_particle_fade:
|
||||
if mat_state.material.lnx_particle_flag and lnx.utils.get_rp().lnx_particles == 'GPU' and mat_state.material.lnx_particle_fade:
|
||||
frag.write('fragColor[0].rgb *= p_fade;')
|
||||
|
||||
|
||||
@ -695,10 +702,10 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False):
|
||||
if '_Brdf' in wrd.world_defs:
|
||||
frag.write('envl.rgb *= 1.0 - F;')
|
||||
if '_Rad' in wrd.world_defs:
|
||||
frag.write('envl += prefilteredColor * F;')
|
||||
frag.write('envl += prefilteredColor * F * 1.5;')
|
||||
elif '_EnvCol' in wrd.world_defs:
|
||||
frag.add_uniform('vec3 backgroundCol', link='_backgroundCol')
|
||||
frag.write('envl += backgroundCol * F;')
|
||||
frag.write('envl += backgroundCol * F * 1.5;')
|
||||
|
||||
frag.add_uniform('float envmapStrength', link='_envmapStrength')
|
||||
frag.write('envl *= envmapStrength * occlusion;')
|
||||
|
||||
@ -43,7 +43,7 @@ def write(vert, particle_info=None, shadowmap=False):
|
||||
for tex_slot in psettings.texture_slots:
|
||||
if not tex_slot: break
|
||||
if not tex_slot.use_map_size: break # TODO: check also for other influences
|
||||
if tex_slot.texture and tex_slot.texture.use_color_ramp:
|
||||
if tex_slot.texture.use_color_ramp:
|
||||
if tex_slot.texture.color_ramp and tex_slot.texture.color_ramp.elements:
|
||||
ramp_el_len = len(tex_slot.texture.color_ramp.elements.items())
|
||||
for element in tex_slot.texture.color_ramp.elements:
|
||||
@ -250,7 +250,7 @@ def write(vert, particle_info=None, shadowmap=False):
|
||||
vert.write('wnormal = normalize(rotate_around(wnormal, r_angle));')
|
||||
|
||||
# Particle fade
|
||||
if mat_state.material.lnx_particle_flag and lnx.utils.get_rp().lnx_particles == 'On' and mat_state.material.lnx_particle_fade:
|
||||
if mat_state.material.lnx_particle_flag and lnx.utils.get_rp().lnx_particles == 'GPU' and mat_state.material.lnx_particle_fade:
|
||||
vert.add_out('float p_fade')
|
||||
vert.write('p_fade = sin(min((p_age / 2) * 3.141592, 3.141592));')
|
||||
|
||||
|
||||
@ -93,7 +93,7 @@ def make_gi(context_id):
|
||||
|
||||
# Voxelized particles
|
||||
particle = mat_state.material.lnx_particle_flag
|
||||
if particle and rpdat.lnx_particles == 'On':
|
||||
if particle and rpdat.lnx_particles == 'GPU':
|
||||
# make_particle.write(vert, particle_info=cycles.particle_info)
|
||||
frag.write_pre = True
|
||||
frag.write('const float p_index = 0;')
|
||||
|
||||
@ -59,6 +59,7 @@ def get_signature(mat, object: bpy.types.Object):
|
||||
sign += mat.lnx_billboard
|
||||
sign += '_skin' if lnx.utils.export_bone_data(object) else '0'
|
||||
sign += '_morph' if lnx.utils.export_morph_targets(object) else '0'
|
||||
# sign += '_tilesheet' if mat.lnx_tilesheet_flag else '0'
|
||||
return sign
|
||||
|
||||
def traverse_tree2(node, ar):
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import bpy
|
||||
import lnx.utils
|
||||
|
||||
if lnx.is_reload(__name__):
|
||||
@ -286,7 +287,8 @@ class Shader:
|
||||
ar[0] = 'floats'
|
||||
ar[1] = ar[1].split('[', 1)[0]
|
||||
elif ar[0] == 'mat4' and '[' in ar[1]:
|
||||
ar[0] = 'floats'
|
||||
if not (ar[1].startswith('LWVPSpot') and not '_Clusters' in bpy.data.worlds['Lnx'].world_defs): #HACK: do not convert mat4 to floats when using single spot lights
|
||||
ar[0] = 'floats'
|
||||
ar[1] = ar[1].split('[', 1)[0]
|
||||
self.context.add_constant(ar[0], ar[1], link=link, default_value=default_value, is_lnx_mat_param=is_lnx_mat_param)
|
||||
if top:
|
||||
|
||||
Reference in New Issue
Block a user