319 lines
10 KiB
Python
319 lines
10 KiB
Python
import os
|
|
from typing import Union
|
|
|
|
import bpy
|
|
|
|
import arm.assets as assets
|
|
import arm.make_world as make_world
|
|
import arm.material.cycles_functions as c_functions
|
|
import arm.material.cycles as c
|
|
from arm.material.parser_state import ParserState
|
|
from arm.material.shader import floatstr, vec3str
|
|
import arm.utils
|
|
import arm.write_probes as write_probes
|
|
|
|
|
|
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)
|
|
|
|
if node.inputs[0].is_linked:
|
|
co = c.parse_vector_input(node.inputs[0])
|
|
else:
|
|
co = 'bposition'
|
|
|
|
# Color
|
|
if out_socket == node.sockets[0]:
|
|
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])
|
|
res = f'tex_brick({co} * {scale}, {col1}, {col2}, {col3})'
|
|
# Fac
|
|
else:
|
|
scale = c.parse_value_input(node.inputs[4])
|
|
res = 'tex_brick_f({0} * {1})'.format(co, scale)
|
|
|
|
if state.sample_bump:
|
|
c.write_bump(node, res)
|
|
|
|
return res
|
|
|
|
|
|
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])
|
|
else:
|
|
co = 'bposition'
|
|
|
|
# Color
|
|
if out_socket == node.sockets[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])
|
|
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)
|
|
|
|
if state.sample_bump:
|
|
c.write_bump(node, res)
|
|
|
|
return res
|
|
|
|
|
|
def parse_tex_environment(node: bpy.types.ShaderNodeTexEnvironment, out_socket: bpy.types.NodeSocket, state: ParserState) -> vec3str:
|
|
# Pass through
|
|
return c.to_vec3([0.0, 0.0, 0.0])
|
|
|
|
|
|
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])
|
|
else:
|
|
co = 'bposition'
|
|
|
|
grad = node.gradient_type
|
|
if grad == 'LINEAR':
|
|
f = f'{co}.x'
|
|
elif grad == 'QUADRATIC':
|
|
f = '0.0'
|
|
elif grad == 'EASING':
|
|
f = '0.0'
|
|
elif grad == 'DIAGONAL':
|
|
f = f'({co}.x + {co}.y) * 0.5'
|
|
elif grad == 'RADIAL':
|
|
f = f'atan({co}.y, {co}.x) / PI2 + 0.5'
|
|
elif grad == 'QUADRATIC_SPHERE':
|
|
f = '0.0'
|
|
else: # SPHERICAL
|
|
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]:
|
|
res = f'vec3(clamp({f}, 0.0, 1.0))'
|
|
# Fac
|
|
else:
|
|
res = f'(clamp({f}, 0.0, 1.0))'
|
|
|
|
if state.sample_bump:
|
|
c.write_bump(node, res)
|
|
|
|
return res
|
|
|
|
|
|
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]
|
|
|
|
# Already fetched
|
|
if c.is_parsed(c.store_var_name(node)):
|
|
if use_color_out:
|
|
return f'{c.store_var_name(node)}.rgb'
|
|
else:
|
|
return f'{c.store_var_name(node)}.a'
|
|
|
|
tex_name = c.node_name(node.name)
|
|
tex = c.make_texture(node, tex_name)
|
|
tex_link = node.name if node.arm_material_param else None
|
|
|
|
if tex is not None:
|
|
state.curshader.write_textures += 1
|
|
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)}.rgb'
|
|
else:
|
|
res = f'{c.texture_store(node, tex, tex_name, tex_link=tex_link)}.a'
|
|
state.curshader.write_textures -= 1
|
|
return res
|
|
|
|
# Empty texture
|
|
elif node.image is None:
|
|
tex = {
|
|
'name': tex_name,
|
|
'file': ''
|
|
}
|
|
if use_color_out:
|
|
return '{0}.rgb'.format(c.texture_store(node, tex, tex_name, to_linear=False, tex_link=tex_link))
|
|
return '{0}.a'.format(c.texture_store(node, tex, tex_name, to_linear=True, tex_link=tex_link))
|
|
|
|
# Pink color for missing texture
|
|
else:
|
|
tex_store = c.store_var_name(node)
|
|
|
|
if use_color_out:
|
|
state.parsed[tex_store] = True
|
|
state.curshader.write_textures += 1
|
|
state.curshader.write(f'vec4 {tex_store} = vec4(1.0, 0.0, 1.0, 1.0);')
|
|
state.curshader.write_textures -= 1
|
|
return f'{tex_store}.rgb'
|
|
else:
|
|
state.curshader.write(f'vec4 {tex_store} = vec4(1.0, 0.0, 1.0, 1.0);')
|
|
return f'{tex_store}.a'
|
|
|
|
|
|
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])
|
|
else:
|
|
co = 'bposition'
|
|
|
|
scale = c.parse_value_input(node.inputs[1])
|
|
|
|
# Color
|
|
if out_socket == node.outputs[0]:
|
|
res = f'tex_magic({co} * {scale} * 4.0)'
|
|
# Fac
|
|
else:
|
|
res = f'tex_magic_f({co} * {scale} * 4.0)'
|
|
|
|
if state.sample_bump:
|
|
c.write_bump(node, res, 0.1)
|
|
|
|
return res
|
|
|
|
|
|
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])
|
|
else:
|
|
co = 'bposition'
|
|
|
|
scale = c.parse_value_input(node.inputs[1])
|
|
# detail = c.parse_value_input(node.inputs[2])
|
|
# distortion = c.parse_value_input(node.inputs[3])
|
|
|
|
# Color
|
|
if out_socket == node.outputs[0]:
|
|
res = f'vec3(tex_musgrave_f({co} * {scale} * 0.5))'
|
|
# Fac
|
|
else:
|
|
res = 'tex_musgrave_f({0} * {1} * 0.5)'.format(co, scale)
|
|
|
|
if state.sample_bump:
|
|
c.write_bump(node, res)
|
|
|
|
return res
|
|
|
|
|
|
def parse_tex_noise(node: bpy.types.ShaderNodeTexNoise, out_socket: bpy.types.NodeSocket, state: ParserState) -> Union[floatstr, vec3str]:
|
|
c.write_procedurals()
|
|
state.curshader.add_function(c_functions.str_tex_noise)
|
|
c.assets_add(os.path.join(c.get_sdk_path(), 'armory', '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])
|
|
else:
|
|
co = 'bposition'
|
|
|
|
scale = c.parse_value_input(node.inputs[2])
|
|
detail = c.parse_value_input(node.inputs[3])
|
|
distortion = c.parse_value_input(node.inputs[4])#
|
|
|
|
# Color
|
|
if out_socket == node.outputs[0]:
|
|
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)
|
|
# Fac
|
|
else:
|
|
res = 'tex_noise({0} * {1},{2},{3})'.format(co, scale, detail, distortion)
|
|
|
|
if state.sample_bump:
|
|
c.write_bump(node, res, 0.1)
|
|
|
|
return res
|
|
|
|
|
|
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]:
|
|
return c.to_vec3([0.0, 0.0, 0.0])
|
|
# Density
|
|
else:
|
|
return '0.0'
|
|
|
|
|
|
def parse_tex_sky(node: bpy.types.ShaderNodeTexSky, out_socket: bpy.types.NodeSocket, state: ParserState) -> vec3str:
|
|
# Pass through
|
|
return c.to_vec3([0.0, 0.0, 0.0])
|
|
|
|
|
|
def parse_tex_voronoi(node: bpy.types.ShaderNodeTexVoronoi, out_socket: bpy.types.NodeSocket, state: ParserState) -> Union[floatstr, vec3str]:
|
|
outp = 0
|
|
if out_socket.type == 'RGBA':
|
|
outp = 1
|
|
elif out_socket.type == 'VECTOR':
|
|
outp = 2
|
|
m = 0
|
|
if node.distance == 'MANHATTAN':
|
|
m = 1
|
|
elif node.distance == 'CHEBYCHEV':
|
|
m = 2
|
|
elif node.distance == 'MINKOWSKI':
|
|
m = 3
|
|
|
|
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])
|
|
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])
|
|
|
|
# Color or Position
|
|
if out_socket == node.outputs[1] or out_socket == node.outputs[2]:
|
|
res = 'tex_voronoi({0}, {1}, {2}, {3}, {4}, {5})'.format(co, randomness, m, outp, scale, exp)
|
|
# Distance
|
|
else:
|
|
res = 'tex_voronoi({0}, {1}, {2}, {3}, {4}, {5}).x'.format(co, randomness, m, outp, scale, exp)
|
|
|
|
if state.sample_bump:
|
|
c.write_bump(node, res)
|
|
|
|
return res
|
|
|
|
|
|
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])
|
|
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])
|
|
if node.wave_profile == 'SIN':
|
|
wave_profile = 0
|
|
else:
|
|
wave_profile = 1
|
|
if node.wave_type == 'BANDS':
|
|
wave_type = 0
|
|
else:
|
|
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)
|
|
# Fac
|
|
else:
|
|
res = 'tex_wave_f({0} * {1},{2},{3},{4},{5},{6})'.format(co, scale, wave_type, wave_profile, distortion, detail, detail_scale)
|
|
|
|
if state.sample_bump:
|
|
c.write_bump(node, res)
|
|
|
|
return res
|