Begin runtime material builder
This commit is contained in:
parent
8c6947f054
commit
64b334b643
1255
Sources/armory/system/Cycles.hx
Normal file
1255
Sources/armory/system/Cycles.hx
Normal file
File diff suppressed because it is too large
Load diff
|
@ -23,7 +23,6 @@ import arm.assets as assets
|
|||
import arm.log as log
|
||||
import arm.material.make as make_material
|
||||
import arm.material.mat_batch as mat_batch
|
||||
import arm.material.texture as make_texture
|
||||
import arm.nodes as nodes
|
||||
import arm.make_renderer as make_renderer
|
||||
import arm.make_renderpath as make_renderpath
|
||||
|
|
|
@ -14,14 +14,8 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
import bpy
|
||||
import arm.utils
|
||||
import arm.assets as assets
|
||||
import arm.make_state as make_state
|
||||
import arm.log as log
|
||||
import arm.material.mat_state as mat_state
|
||||
import arm.material.texture as texture
|
||||
import arm.material.functions as functions
|
||||
import arm.material.cycles_functions as c_functions
|
||||
import arm.material.cycles_state as c_state
|
||||
|
||||
def parse(nodes, vert, frag, geom, tesc, tese, parse_surface=True, parse_opacity=True, parse_displacement=True):
|
||||
output_node = node_by_type(nodes, 'OUTPUT_MATERIAL')
|
||||
|
@ -72,7 +66,7 @@ def parse_output(node, _vert, _frag, _geom, _tesc, _tese, _parse_surface, _parse
|
|||
# parse_volume_input(node.inputs[1])
|
||||
|
||||
# Displacement
|
||||
if parse_displacement and arm.utils.tess_enabled(make_state.target) and node.inputs[2].is_linked and tese != None:
|
||||
if parse_displacement and c_state.tess_enabled() and node.inputs[2].is_linked and tese != None:
|
||||
parsed = []
|
||||
parents = []
|
||||
normal_written = False
|
||||
|
@ -166,7 +160,7 @@ def parse_shader(node, socket):
|
|||
out_metallic = parse_value_input(node.inputs[5])
|
||||
# Normal
|
||||
if node.inputs[6].is_linked and node.inputs[6].links[0].from_node.type == 'NORMAL_MAP':
|
||||
log.warn(mat_state.material.name + ' - Do not use Normal Map node with Armory PBR, connect Image Texture directly')
|
||||
c_state.warn(c_state.mat_name() + ' - Do not use Normal Map node with Armory PBR, connect Image Texture directly')
|
||||
parse_normal_map_color_input(node.inputs[6], node.inputs[7])
|
||||
# Emission
|
||||
if node.inputs[8].is_linked:
|
||||
|
@ -326,7 +320,7 @@ def parse_displacement_input(inp):
|
|||
return None
|
||||
|
||||
def res_var_name(node, socket):
|
||||
return node_name(node.name) + '_' + socket_name(socket.name) + '_res'
|
||||
return node_name(node.name) + '_' + c_state.safe_source_name(socket.name) + '_res'
|
||||
|
||||
def write_result(l):
|
||||
res_var = res_var_name(l.from_node, l.from_socket)
|
||||
|
@ -364,7 +358,7 @@ def glsltype(t):
|
|||
return 'float'
|
||||
|
||||
def touniform(inp):
|
||||
uname = arm.utils.safe_source_name(inp.node.name) + arm.utils.safe_source_name(inp.name)
|
||||
uname = c_state.safe_source_name(inp.node.name) + c_state.safe_source_name(inp.name)
|
||||
curshader.add_uniform(glsltype(inp.type) + ' ' + uname)
|
||||
return uname
|
||||
|
||||
|
@ -385,7 +379,7 @@ def parse_vector_input(inp):
|
|||
if inp.type == 'VALUE': # Unlinked reroute
|
||||
return tovec3([0.0, 0.0, 0.0])
|
||||
else:
|
||||
if mat_state.batch and inp.is_uniform:
|
||||
if c_state.mat_batch() and inp.is_uniform:
|
||||
return touniform(inp)
|
||||
else:
|
||||
return tovec3(inp.default_value)
|
||||
|
@ -401,7 +395,7 @@ def parse_rgb(node, socket):
|
|||
elif node.type == 'ATTRIBUTE':
|
||||
# Vcols only for now
|
||||
# node.attribute_name
|
||||
mat_state.data.add_elem('col', 3)
|
||||
c_state.mat_add_elem('col', 3)
|
||||
return 'vcolor'
|
||||
|
||||
elif node.type == 'RGB':
|
||||
|
@ -412,7 +406,7 @@ def parse_rgb(node, socket):
|
|||
return tovec3([0.0, 0.0, 0.0])
|
||||
|
||||
elif node.type == 'TEX_CHECKER':
|
||||
curshader.add_function(functions.str_tex_checker)
|
||||
curshader.add_function(c_functions.str_tex_checker)
|
||||
if node.inputs[0].is_linked:
|
||||
co = parse_vector_input(node.inputs[0])
|
||||
else:
|
||||
|
@ -452,8 +446,8 @@ def parse_rgb(node, socket):
|
|||
# Already fetched
|
||||
if res_var_name(node, node.outputs[1]) in parsed:
|
||||
return '{0}.rgb'.format(store_var_name(node))
|
||||
tex_name = arm.utils.safe_source_name(node.name)
|
||||
tex = texture.make_texture(node, tex_name)
|
||||
tex_name = c_state.safe_source_name(node.name)
|
||||
tex = c_state.make_texture(node, tex_name)
|
||||
if tex != None:
|
||||
to_linear = parsing_basecol and not tex['file'].endswith('.hdr')
|
||||
return '{0}.rgb'.format(texture_store(node, tex, tex_name, to_linear))
|
||||
|
@ -473,7 +467,7 @@ def parse_rgb(node, socket):
|
|||
|
||||
elif node.type == 'TEX_MUSGRAVE':
|
||||
# Fall back to noise
|
||||
curshader.add_function(functions.str_tex_noise)
|
||||
curshader.add_function(c_functions.str_tex_noise)
|
||||
if node.inputs[0].is_linked:
|
||||
co = parse_vector_input(node.inputs[0])
|
||||
else:
|
||||
|
@ -484,7 +478,7 @@ def parse_rgb(node, socket):
|
|||
return 'vec3(tex_noise_f({0} * {1}))'.format(co, scale)
|
||||
|
||||
elif node.type == 'TEX_NOISE':
|
||||
curshader.add_function(functions.str_tex_noise)
|
||||
curshader.add_function(c_functions.str_tex_noise)
|
||||
if node.inputs[0].is_linked:
|
||||
co = parse_vector_input(node.inputs[0])
|
||||
else:
|
||||
|
@ -504,9 +498,9 @@ def parse_rgb(node, socket):
|
|||
return tovec3([0.0, 0.0, 0.0])
|
||||
|
||||
elif node.type == 'TEX_VORONOI':
|
||||
curshader.add_function(functions.str_tex_voronoi)
|
||||
assets.add(arm.utils.get_sdk_path() + '/armory/Assets/' + 'noise64.png')
|
||||
assets.add_embedded_data('noise64.png')
|
||||
curshader.add_function(c_functions.str_tex_voronoi)
|
||||
c_state.assets_add(c_state.get_sdk_path() + '/armory/Assets/' + 'noise64.png')
|
||||
c_state.assets_add_embedded_data('noise64.png')
|
||||
curshader.add_uniform('sampler2D snoise', link='_noise64')
|
||||
if node.inputs[0].is_linked:
|
||||
co = parse_vector_input(node.inputs[0])
|
||||
|
@ -541,7 +535,7 @@ def parse_rgb(node, socket):
|
|||
return 'pow({0}, vec3({1}))'.format(out_col, gamma)
|
||||
|
||||
elif node.type == 'HUE_SAT':
|
||||
curshader.add_function(functions.str_hsv_to_rgb)
|
||||
curshader.add_function(c_functions.str_hsv_to_rgb)
|
||||
hue = parse_value_input(node.inputs[0])
|
||||
sat = parse_value_input(node.inputs[1])
|
||||
val = parse_value_input(node.inputs[2])
|
||||
|
@ -667,15 +661,15 @@ def store_var_name(node):
|
|||
|
||||
def texture_store(node, tex, tex_name, to_linear=False):
|
||||
global parse_teximage_vector
|
||||
mat_state.bind_textures.append(tex)
|
||||
mat_state.data.add_elem('tex', 2)
|
||||
c_state.mat_bind_texture(tex)
|
||||
c_state.mat_add_elem('tex', 2)
|
||||
curshader.add_uniform('sampler2D {0}'.format(tex_name))
|
||||
if node.inputs[0].is_linked and parse_teximage_vector:
|
||||
uv_name = parse_vector_input(node.inputs[0])
|
||||
else:
|
||||
uv_name = 'texCoord'
|
||||
tex_store = store_var_name(node)
|
||||
if mat_state.texture_grad:
|
||||
if c_state.mat_texture_grad():
|
||||
curshader.write('vec4 {0} = textureGrad({1}, {2}.xy, g2.xy, g2.zw);'.format(tex_store, tex_name, uv_name))
|
||||
else:
|
||||
curshader.write('vec4 {0} = texture({1}, {2}.xy);'.format(tex_store, tex_name, uv_name))
|
||||
|
@ -693,16 +687,16 @@ def parse_vector(node, socket):
|
|||
|
||||
elif node.type == 'ATTRIBUTE':
|
||||
# UVMaps only for now
|
||||
mat_state.data.add_elem('tex', 2)
|
||||
mat = mat_state.material
|
||||
mat_users = mat_state.mat_users
|
||||
c_state.mat_add_elem('tex', 2)
|
||||
mat = c_state.mat_get_material()
|
||||
mat_users = c_state.mat_get_material_users()
|
||||
if mat_users != None and mat in mat_users:
|
||||
mat_user = mat_users[mat][0]
|
||||
if hasattr(mat_user.data, 'uv_layers'): # No uvlayers for Curve
|
||||
lays = mat_user.data.uv_layers
|
||||
# Second uvmap referenced
|
||||
if len(lays) > 1 and node.attribute_name == lays[1].name:
|
||||
mat_state.data.add_elem('tex1', 2)
|
||||
c_state.mat_add_elem('tex1', 2)
|
||||
return 'texCoord1', 2
|
||||
return 'texCoord', 2
|
||||
|
||||
|
@ -749,7 +743,7 @@ def parse_vector(node, socket):
|
|||
elif socket == node.outputs[1]: # Normal
|
||||
return 'vec2(0.0)', 2
|
||||
elif socket == node.outputs[2]: # UV
|
||||
mat_state.data.add_elem('tex', 2)
|
||||
c_state.mat_add_elem('tex', 2)
|
||||
return 'texCoord', 2
|
||||
elif socket == node.outputs[3]: # Object
|
||||
return 'vec2(0.0)', 2
|
||||
|
@ -835,8 +829,8 @@ def parse_normal_map_color_input(inp, str_inp=None):
|
|||
return
|
||||
frag.write_pre = True
|
||||
parse_teximage_vector = False # Force texCoord for normal map image vector
|
||||
defplus = bpy.data.cameras[0].rp_renderer == 'Deferred Plus'
|
||||
if not bpy.data.worlds['Arm'].arm_export_tangents or defplus: # Compute TBN matrix
|
||||
defplus = c_state.get_rp_renderer() == 'Deferred Plus'
|
||||
if not c_state.get_arm_export_tangents() or defplus: # Compute TBN matrix
|
||||
frag.write('vec3 texn = ({0}) * 2.0 - 1.0;'.format(parse_vector_input(inp)))
|
||||
frag.add_include('../../Shaders/std/normals.glsl')
|
||||
if defplus:
|
||||
|
@ -848,7 +842,7 @@ def parse_normal_map_color_input(inp, str_inp=None):
|
|||
frag.write('vec3 n = ({0}) * 2.0 - 1.0;'.format(parse_vector_input(inp)))
|
||||
# frag.write('n = normalize(TBN * normalize(n));')
|
||||
frag.write('n = TBN * normalize(n);')
|
||||
mat_state.data.add_elem('tang', 3)
|
||||
c_state.mat_add_elem('tang', 3)
|
||||
|
||||
parse_teximage_vector = True
|
||||
frag.write_pre = False
|
||||
|
@ -867,7 +861,7 @@ def parse_value_input(inp):
|
|||
else: # VALUE
|
||||
return res_var
|
||||
else:
|
||||
if mat_state.batch and inp.is_uniform:
|
||||
if c_state.mat_batch() and inp.is_uniform:
|
||||
return touniform(inp)
|
||||
else:
|
||||
return tovec1(inp.default_value)
|
||||
|
@ -989,7 +983,7 @@ def parse_value(node, socket):
|
|||
|
||||
elif node.type == 'TEX_CHECKER':
|
||||
# TODO: do not recompute when color socket is also connected
|
||||
curshader.add_function(functions.str_tex_checker)
|
||||
curshader.add_function(c_functions.str_tex_checker)
|
||||
if node.inputs[0].is_linked:
|
||||
co = parse_vector_input(node.inputs[0])
|
||||
else:
|
||||
|
@ -1006,8 +1000,8 @@ def parse_value(node, socket):
|
|||
# Already fetched
|
||||
if res_var_name(node, node.outputs[0]) in parsed:
|
||||
return '{0}.a'.format(store_var_name(node))
|
||||
tex_name = arm.utils.safe_source_name(node.name)
|
||||
tex = texture.make_texture(node, tex_name)
|
||||
tex_name = c_state.safe_source_name(node.name)
|
||||
tex = c_state.make_texture(node, tex_name)
|
||||
if tex != None:
|
||||
return '{0}.a'.format(texture_store(node, tex, tex_name))
|
||||
else:
|
||||
|
@ -1020,7 +1014,7 @@ def parse_value(node, socket):
|
|||
|
||||
elif node.type == 'TEX_MUSGRAVE':
|
||||
# Fall back to noise
|
||||
curshader.add_function(functions.str_tex_noise)
|
||||
curshader.add_function(c_functions.str_tex_noise)
|
||||
if node.inputs[0].is_linked:
|
||||
co = parse_vector_input(node.inputs[0])
|
||||
else:
|
||||
|
@ -1031,7 +1025,7 @@ def parse_value(node, socket):
|
|||
return 'tex_noise_f({0} * {1})'.format(co, scale)
|
||||
|
||||
elif node.type == 'TEX_NOISE':
|
||||
curshader.add_function(functions.str_tex_noise)
|
||||
curshader.add_function(c_functions.str_tex_noise)
|
||||
if node.inputs[0].is_linked:
|
||||
co = parse_vector_input(node.inputs[0])
|
||||
else:
|
||||
|
@ -1045,9 +1039,9 @@ def parse_value(node, socket):
|
|||
return '0.0'
|
||||
|
||||
elif node.type == 'TEX_VORONOI':
|
||||
curshader.add_function(functions.str_tex_voronoi)
|
||||
assets.add(arm.utils.get_sdk_path() + '/armory/Assets/' + 'noise64.png')
|
||||
assets.add_embedded_data('noise64.png')
|
||||
curshader.add_function(c_functions.str_tex_voronoi)
|
||||
c_state.assets_add(c_state.get_sdk_path() + '/armory/Assets/' + 'noise64.png')
|
||||
c_state.assets_add_embedded_data('noise64.png')
|
||||
curshader.add_uniform('sampler2D snoise', link='_noise64')
|
||||
if node.inputs[0].is_linked:
|
||||
co = parse_vector_input(node.inputs[0])
|
||||
|
@ -1180,10 +1174,7 @@ def socket_index(node, socket):
|
|||
return i
|
||||
|
||||
def node_name(s):
|
||||
s = arm.utils.safe_source_name(s)
|
||||
s = c_state.safe_source_name(s)
|
||||
if len(parents) > 0:
|
||||
s = arm.utils.safe_source_name(parents[-1].name) + '_' + s
|
||||
s = c_state.safe_source_name(parents[-1].name) + '_' + s
|
||||
return s
|
||||
|
||||
def socket_name(s):
|
||||
return arm.utils.safe_source_name(s)
|
||||
|
|
55
blender/arm/material/cycles_state.py
Normal file
55
blender/arm/material/cycles_state.py
Normal file
|
@ -0,0 +1,55 @@
|
|||
import bpy
|
||||
import arm.assets
|
||||
import arm.utils
|
||||
import arm.make_state
|
||||
import arm.log
|
||||
import arm.material.make_texture
|
||||
import arm.material.mat_state as mat_state
|
||||
|
||||
def get_rp_renderer():
|
||||
return bpy.data.cameras[0].rp_renderer
|
||||
|
||||
def get_arm_export_tangents():
|
||||
return bpy.data.worlds['Arm'].arm_export_tangents
|
||||
|
||||
def safe_source_name(name):
|
||||
return arm.utils.safe_source_name(name)
|
||||
|
||||
def get_sdk_path():
|
||||
return arm.utils.get_sdk_path()
|
||||
|
||||
def tess_enabled():
|
||||
return arm.utils.tess_enabled(arm.make_state.target)
|
||||
|
||||
def warn(text):
|
||||
arm.log.warn(text)
|
||||
|
||||
def assets_add(path):
|
||||
arm.assets.add(path)
|
||||
|
||||
def assets_add_embedded_data(path):
|
||||
arm.assets.add_embedded_data(path)
|
||||
|
||||
def make_texture(node, name):
|
||||
return arm.material.make_texture.make(node, name)
|
||||
|
||||
def mat_name():
|
||||
return mat_state.material.name
|
||||
|
||||
def mat_batch():
|
||||
return mat_state.batch
|
||||
|
||||
def mat_add_elem(name, size):
|
||||
mat_state.data.add_elem(name, size)
|
||||
|
||||
def mat_bind_texture(tex):
|
||||
mat_state.bind_textures.append(tex)
|
||||
|
||||
def mat_texture_grad():
|
||||
return mat_state.texture_grad
|
||||
|
||||
def mat_get_material():
|
||||
return mat_state.material
|
||||
|
||||
def mat_get_material_users():
|
||||
return mat_state.mat_users
|
|
@ -3,7 +3,7 @@ import arm.utils
|
|||
import arm.material.make_shader as make_shader
|
||||
import arm.material.mat_batch as mat_batch
|
||||
import arm.material.mat_state as mat_state
|
||||
import arm.material.texture as texture
|
||||
import arm.material.make_texture as make_texture
|
||||
|
||||
def glsltype(t): # Merge with cycles
|
||||
if t == 'RGB' or t == 'RGBA' or t == 'VECTOR':
|
||||
|
@ -52,7 +52,7 @@ def parse(material, mat_data, mat_users, mat_armusers, rid):
|
|||
for node in material.node_tree.nodes:
|
||||
if node.type == 'TEX_IMAGE':
|
||||
tex_name = arm.utils.safe_source_name(node.name)
|
||||
tex = texture.make_texture(node, tex_name)
|
||||
tex = make_texture.make(node, tex_name)
|
||||
if tex == None: # Empty texture
|
||||
tex = {}
|
||||
tex['name'] = tex_name
|
||||
|
|
|
@ -8,6 +8,7 @@ import arm.material.make_tess as make_tess
|
|||
import arm.utils
|
||||
|
||||
is_displacement = False
|
||||
write_material_attribs = None
|
||||
|
||||
def make(context_id, rid):
|
||||
con_mesh = mat_state.data.add_context({ 'name': context_id, 'depth_write': True, 'compare_mode': 'less', 'cull_mode': 'clockwise' })
|
||||
|
@ -68,6 +69,7 @@ def make_finalize(con_mesh):
|
|||
|
||||
def make_base(con_mesh, parse_opacity):
|
||||
global is_displacement
|
||||
global write_material_attribs
|
||||
|
||||
vert = con_mesh.make_vert()
|
||||
frag = con_mesh.make_frag()
|
||||
|
@ -107,14 +109,16 @@ def make_base(con_mesh, parse_opacity):
|
|||
|
||||
frag.add_include('../../Shaders/compiled.glsl')
|
||||
|
||||
frag.write('vec3 basecol;')
|
||||
frag.write('float roughness;')
|
||||
frag.write('float metallic;')
|
||||
frag.write('float occlusion;')
|
||||
if parse_opacity:
|
||||
frag.write('float opacity;')
|
||||
|
||||
cycles.parse(mat_state.nodes, vert, frag, geom, tesc, tese, parse_opacity=parse_opacity)
|
||||
if write_material_attribs != None:
|
||||
write_material_attribs(frag)
|
||||
else:
|
||||
frag.write('vec3 basecol;')
|
||||
frag.write('float roughness;')
|
||||
frag.write('float metallic;')
|
||||
frag.write('float occlusion;')
|
||||
if parse_opacity:
|
||||
frag.write('float opacity;')
|
||||
cycles.parse(mat_state.nodes, vert, frag, geom, tesc, tese, parse_opacity=parse_opacity)
|
||||
|
||||
if mat_state.data.is_elem('tex'):
|
||||
vert.add_out('vec2 texCoord')
|
||||
|
|
|
@ -16,7 +16,6 @@ import arm.material.make_decal as make_decal
|
|||
import arm.material.make_voxel as make_voxel
|
||||
|
||||
rpass_hook = None
|
||||
mesh_make = make_mesh.make
|
||||
|
||||
def build(material, mat_users, mat_armusers, rid):
|
||||
mat_state.mat_users = mat_users
|
||||
|
@ -62,7 +61,7 @@ def build(material, mat_users, mat_armusers, rid):
|
|||
mat_state.bind_textures = tar
|
||||
|
||||
if rp == 'mesh':
|
||||
con = mesh_make(rp, rid)
|
||||
con = make_mesh.make(rp, rid)
|
||||
|
||||
elif rp == 'rect':
|
||||
con = make_rect.make(rp)
|
||||
|
|
|
@ -6,7 +6,7 @@ import arm.assets as assets
|
|||
import arm.material.mat_state as mat_state
|
||||
import arm.make_state as state
|
||||
|
||||
def make_texture(image_node, tex_name, matname=None):
|
||||
def make(image_node, tex_name, matname=None):
|
||||
wrd = bpy.data.worlds['Arm']
|
||||
tex = {}
|
||||
tex['name'] = tex_name
|
|
@ -432,7 +432,7 @@ class ArmoryProjectPanel(bpy.types.Panel):
|
|||
layout.prop(wrd, 'arm_project_name')
|
||||
layout.prop(wrd, 'arm_project_package')
|
||||
layout.prop_search(wrd, 'arm_khafile', bpy.data, 'texts', 'Khafile')
|
||||
layout.prop_search(wrd, 'arm_command_line', bpy.data, 'texts', 'Command Line')
|
||||
layout.prop_search(wrd, 'arm_khamake', bpy.data, 'texts', 'Khamake')
|
||||
row = layout.row(align=True)
|
||||
row.operator("arm.kode_studio")
|
||||
row.operator("arm.open_project_folder")
|
||||
|
|
Loading…
Reference in a new issue