mirror of
https://github.com/Relintai/material-maker.git
synced 2024-12-23 21:16:54 +01:00
Merge pull request #93 from RodZill4/dev-export
Added export for Godot, Unity and Unreal and command line arguments support
This commit is contained in:
commit
59c9e3b7b1
@ -228,12 +228,15 @@ func _serialize(data: Dictionary) -> Dictionary:
|
||||
print("cannot save "+name)
|
||||
return data
|
||||
|
||||
func _serialize_data(data: Dictionary) -> Dictionary:
|
||||
return data
|
||||
|
||||
func serialize() -> Dictionary:
|
||||
var rv = { name=name, type=get_type(), parameters={}, node_position={ x=position.x, y=position.y } }
|
||||
for p in get_parameter_defs():
|
||||
if parameters.has(p.name):
|
||||
rv.parameters[p.name] = MMType.serialize_value(parameters[p.name])
|
||||
else:
|
||||
elif p.has("default"):
|
||||
rv.parameters[p.name] = p.default
|
||||
if seed_locked:
|
||||
rv.seed_value = seed_value
|
||||
@ -241,6 +244,7 @@ func serialize() -> Dictionary:
|
||||
rv.type = model
|
||||
else:
|
||||
rv = _serialize(rv)
|
||||
rv = _serialize_data(rv)
|
||||
return rv
|
||||
|
||||
func _deserialize(_data : Dictionary) -> void:
|
||||
|
@ -34,19 +34,13 @@ func get_parameter_defs() -> Array:
|
||||
func get_input_defs() -> Array:
|
||||
return [ { name="in", type="rgba" } ]
|
||||
|
||||
func render_textures() -> void:
|
||||
func export_material(prefix : String, _profile : String, size : int = 0) -> void:
|
||||
if size == 0:
|
||||
size = get_image_size()
|
||||
var source = get_source(0)
|
||||
if source != null:
|
||||
var result = source.generator.render(source.output_index, get_image_size())
|
||||
var result = source.generator.render(source.output_index, size)
|
||||
while result is GDScriptFunctionState:
|
||||
result = yield(result, "completed")
|
||||
texture = ImageTexture.new()
|
||||
result.copy_to_texture(texture)
|
||||
result.save_to_file("%s_%s.png" % [ prefix, parameters.suffix])
|
||||
result.release()
|
||||
else:
|
||||
texture = null
|
||||
|
||||
func export_textures(prefix, __ = null) -> void:
|
||||
if texture != null:
|
||||
var image = texture.get_data()
|
||||
image.save_png("%s_%s.png" % [ prefix, parameters.suffix])
|
||||
|
@ -1,19 +1,30 @@
|
||||
tool
|
||||
extends MMGenBase
|
||||
extends MMGenShader
|
||||
class_name MMGenMaterial
|
||||
|
||||
var export_paths = {}
|
||||
|
||||
var material : SpatialMaterial
|
||||
var generated_textures = {}
|
||||
|
||||
const TEXTURE_LIST = [
|
||||
{ port=0, texture="albedo" },
|
||||
{ port=3, texture="emission" },
|
||||
{ port=4, texture="normal" },
|
||||
{ ports=[5, 2, 1], default_values=["1.0", "1.0", "1.0"], texture="orm" },
|
||||
{ port=6, texture="depth" },
|
||||
{ port=7, texture="subsurf_scatter" }
|
||||
{ port=0, texture="albedo", sources=[0] },
|
||||
{ port=1, texture="orm", sources=[1, 2, 5] },
|
||||
{ port=2, texture="emission", sources=[3] },
|
||||
{ port=3, texture="normal", sources=[4] },
|
||||
{ port=4, texture="depth", sources=[6] },
|
||||
{ port=5, texture="sss", sources=[7] }
|
||||
]
|
||||
|
||||
const INPUT_ALBEDO : int = 0
|
||||
const INPUT_METALLIC : int = 1
|
||||
const INPUT_ROUGHNESS : int = 2
|
||||
const INPUT_EMISSION : int = 3
|
||||
const INPUT_NORMAL : int = 4
|
||||
const INPUT_OCCLUSION : int = 5
|
||||
const INPUT_DEPTH : int = 6
|
||||
const INPUT_SSS : int = 7
|
||||
|
||||
# The minimum allowed texture size as a power-of-two exponent
|
||||
const TEXTURE_SIZE_MIN = 4 # 16x16
|
||||
|
||||
@ -23,6 +34,7 @@ const TEXTURE_SIZE_MAX = 12 # 4096x4096
|
||||
# The default texture size as a power-of-two exponent
|
||||
const TEXTURE_SIZE_DEFAULT = 10 # 1024x1024
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
for t in TEXTURE_LIST:
|
||||
generated_textures[t.texture] = null
|
||||
@ -37,30 +49,8 @@ func get_type() -> String:
|
||||
func get_type_name() -> String:
|
||||
return "Material"
|
||||
|
||||
func get_parameter_defs() -> Array:
|
||||
return [
|
||||
{ name="albedo_color", label="Albedo", type="color", default={ r=1.0, g=1.0, b=1.0, a=1.0} },
|
||||
{ name="metallic", label="Metallic", type="float", min=0.0, max=1.0, step=0.05, default=1.0 },
|
||||
{ name="roughness", label="Roughness", type="float", min=0.0, max=1.0, step=0.05, default=1.0 },
|
||||
{ name="emission_energy", label="Emission", type="float", min=0.0, max=8.0, step=0.05, default=1.0 },
|
||||
{ name="normal_scale", label="Normal", type="float", min=0.0, max=8.0, step=0.05, default=1.0 },
|
||||
{ name="ao_light_affect", label="Ambient occlusion", type="float", min=0.0, max=1.0, step=0.05, default=1.0 },
|
||||
{ name="depth_scale", label="Depth", type="float", min=0.0, max=1.0, step=0.05, default=1.0 },
|
||||
{ name="subsurf_scatter_strength", label="Subsurf. Scatter.", type="float", min=0.0, max=1.0, step=0.05, default=0.0 },
|
||||
{ name="size", label="Size", type="size", first=TEXTURE_SIZE_MIN, last=TEXTURE_SIZE_MAX, default=TEXTURE_SIZE_DEFAULT }
|
||||
]
|
||||
|
||||
func get_input_defs() -> Array:
|
||||
return [
|
||||
{ name="albedo_texture", label="", type="rgb" },
|
||||
{ name="metallic_texture", label="", type="f" },
|
||||
{ name="roughness_texture", label="", type="f" },
|
||||
{ name="emission_texture", label="", type="rgb" },
|
||||
{ name="normal_texture", label="", type="rgb" },
|
||||
{ name="ao_texture", label="", type="f" },
|
||||
{ name="depth_texture", label="", type="f" },
|
||||
{ name="subsurf_scatter_texture", label="", type="f" }
|
||||
]
|
||||
func get_output_defs() -> Array:
|
||||
return []
|
||||
|
||||
func get_image_size() -> int:
|
||||
var rv : int
|
||||
@ -83,9 +73,7 @@ func set_parameter(p, v) -> void:
|
||||
|
||||
func source_changed(input_index : int) -> void:
|
||||
for t in TEXTURE_LIST:
|
||||
if t.has("port") and t.port == input_index:
|
||||
generated_textures[t.texture] = null
|
||||
elif t.has("ports") and t.ports.has(input_index):
|
||||
if t.has("sources") and t.sources.find(input_index) != -1:
|
||||
generated_textures[t.texture] = null
|
||||
update_preview()
|
||||
|
||||
@ -96,37 +84,10 @@ func render_textures() -> void:
|
||||
if t.has("port"):
|
||||
if generated_textures[t.texture] != null:
|
||||
continue
|
||||
var source = get_source(t.port)
|
||||
if source == null:
|
||||
generated_textures[t.texture] = null
|
||||
continue
|
||||
result = source.generator.render(source.output_index, get_image_size())
|
||||
elif t.has("ports"):
|
||||
var context : MMGenContext = MMGenContext.new()
|
||||
var code = []
|
||||
var shader_textures = {}
|
||||
var sources = 0
|
||||
for i in range(t.ports.size()):
|
||||
var source = get_source(t.ports[i])
|
||||
if source != null:
|
||||
var status = source.generator.get_shader_code("UV", source.output_index, context)
|
||||
while status is GDScriptFunctionState:
|
||||
status = yield(status, "completed")
|
||||
code.push_back(status)
|
||||
for t in status.textures.keys():
|
||||
shader_textures[t] = status.textures[t]
|
||||
sources += 1
|
||||
else:
|
||||
code.push_back({ defs="", code="", f=t.default_values[i] })
|
||||
if sources == 0:
|
||||
generated_textures[t.texture] = null
|
||||
continue
|
||||
var shader : String = mm_renderer.generate_combined_shader(code[0], code[1], code[2])
|
||||
result = mm_renderer.render_shader(shader, shader_textures, get_image_size())
|
||||
result = render(t.port, get_image_size())
|
||||
else:
|
||||
generated_textures[t.texture] = null
|
||||
continue
|
||||
|
||||
while result is GDScriptFunctionState:
|
||||
result = yield(result, "completed")
|
||||
texture = ImageTexture.new()
|
||||
@ -143,8 +104,9 @@ func render_textures() -> void:
|
||||
generated_textures[t.texture] = texture
|
||||
|
||||
func update_materials(material_list) -> void:
|
||||
render_textures()
|
||||
for m in material_list:
|
||||
update_spatial_material(m)
|
||||
update_material(m)
|
||||
|
||||
func get_generated_texture(slot, file_prefix = null) -> ImageTexture:
|
||||
if file_prefix != null:
|
||||
@ -157,62 +119,63 @@ func get_generated_texture(slot, file_prefix = null) -> ImageTexture:
|
||||
else:
|
||||
return generated_textures[slot]
|
||||
|
||||
func update_spatial_material(m, file_prefix = null) -> void:
|
||||
func update_material(m, file_prefix = null) -> void:
|
||||
var texture
|
||||
|
||||
if m is SpatialMaterial:
|
||||
# Make the material double-sided for better visiblity in the preview
|
||||
m.params_cull_mode = SpatialMaterial.CULL_DISABLED
|
||||
# Albedo
|
||||
m.albedo_color = parameters.albedo_color
|
||||
m.albedo_texture = get_generated_texture("albedo", file_prefix)
|
||||
m.metallic = parameters.metallic
|
||||
m.roughness = parameters.roughness
|
||||
# Metallic
|
||||
texture = get_generated_texture("orm", file_prefix)
|
||||
m.metallic_texture = texture
|
||||
m.metallic_texture_channel = SpatialMaterial.TEXTURE_CHANNEL_BLUE
|
||||
# Roughness
|
||||
m.roughness_texture = texture
|
||||
m.roughness_texture_channel = SpatialMaterial.TEXTURE_CHANNEL_GREEN
|
||||
# Emission
|
||||
texture = get_generated_texture("emission", file_prefix)
|
||||
if texture != null:
|
||||
m.emission_enabled = true
|
||||
m.emission_energy = parameters.emission_energy
|
||||
m.emission_texture = texture
|
||||
else:
|
||||
m.emission_enabled = false
|
||||
# Normal map
|
||||
texture = get_generated_texture("normal", file_prefix)
|
||||
if texture != null:
|
||||
m.normal_enabled = true
|
||||
m.normal_texture = texture
|
||||
else:
|
||||
m.normal_enabled = false
|
||||
# Ambient occlusion
|
||||
if get_source(5) != null:
|
||||
if get_source(INPUT_OCCLUSION) != null:
|
||||
m.ao_enabled = true
|
||||
m.ao_light_affect = parameters.ao_light_affect
|
||||
m.ao_texture = m.metallic_texture
|
||||
m.ao_light_affect = parameters.ao
|
||||
m.ao_texture = get_generated_texture("orm", file_prefix)
|
||||
m.ao_texture_channel = SpatialMaterial.TEXTURE_CHANNEL_RED
|
||||
else:
|
||||
m.ao_enabled = false
|
||||
# Roughness
|
||||
m.roughness = parameters.roughness
|
||||
if get_source(INPUT_ROUGHNESS) != null:
|
||||
m.roughness_texture = get_generated_texture("orm", file_prefix)
|
||||
m.roughness_texture_channel = SpatialMaterial.TEXTURE_CHANNEL_GREEN
|
||||
else:
|
||||
m.roughness_texture = null
|
||||
# Metallic
|
||||
m.metallic = parameters.metallic
|
||||
if get_source(INPUT_METALLIC) != null:
|
||||
m.metallic_texture = get_generated_texture("orm", file_prefix)
|
||||
m.metallic_texture_channel = SpatialMaterial.TEXTURE_CHANNEL_BLUE
|
||||
else:
|
||||
m.metallic_texture = null
|
||||
# Emission
|
||||
if get_source(INPUT_EMISSION) != null:
|
||||
m.emission_enabled = true
|
||||
m.emission_energy = parameters.emission_energy
|
||||
m.emission_texture = get_generated_texture("emission", file_prefix)
|
||||
else:
|
||||
m.emission_enabled = false
|
||||
# Normal map
|
||||
if get_source(INPUT_NORMAL) != null:
|
||||
m.normal_enabled = true
|
||||
m.normal_texture = get_generated_texture("normal", file_prefix)
|
||||
m.normal_scale = parameters.normal
|
||||
else:
|
||||
m.normal_enabled = false
|
||||
# Depth
|
||||
texture = get_generated_texture("depth", file_prefix)
|
||||
if texture != null and parameters.depth_scale > 0:
|
||||
if get_source(INPUT_DEPTH) != null and parameters.depth_scale > 0:
|
||||
m.depth_enabled = true
|
||||
m.depth_deep_parallax = true
|
||||
m.depth_scale = parameters.depth_scale * 0.2
|
||||
m.depth_texture = texture
|
||||
m.depth_texture = get_generated_texture("depth", file_prefix)
|
||||
else:
|
||||
m.depth_enabled = false
|
||||
# Subsurface scattering
|
||||
texture = get_generated_texture("subsurf_scatter", file_prefix)
|
||||
if texture != null:
|
||||
if get_source(INPUT_SSS) != null:
|
||||
m.subsurf_scatter_enabled = true
|
||||
m.subsurf_scatter_strength = parameters.subsurf_scatter_strength
|
||||
m.subsurf_scatter_texture = texture
|
||||
m.subsurf_scatter_strength = parameters.sss
|
||||
m.subsurf_scatter_texture = get_generated_texture("sss", file_prefix)
|
||||
else:
|
||||
m.subsurf_scatter_enabled = false
|
||||
else:
|
||||
@ -231,25 +194,149 @@ func update_spatial_material(m, file_prefix = null) -> void:
|
||||
m.set_shader_param("depth_scale", parameters.depth_scale * 0.2)
|
||||
m.set_shader_param("texture_depth", get_generated_texture("depth", file_prefix))
|
||||
|
||||
func export_textures(prefix, editor_interface = null) -> SpatialMaterial:
|
||||
for t in TEXTURE_LIST:
|
||||
var texture = generated_textures[t.texture]
|
||||
if texture != null:
|
||||
var image = texture.get_data()
|
||||
image.save_png("%s_%s.png" % [ prefix, t.texture ])
|
||||
if Engine.editor_hint and editor_interface != null:
|
||||
var resource_filesystem = editor_interface.get_resource_filesystem()
|
||||
resource_filesystem.scan()
|
||||
yield(resource_filesystem, "resources_reimported")
|
||||
print("resources_reimported")
|
||||
var new_material = SpatialMaterial.new()
|
||||
update_spatial_material(new_material, prefix)
|
||||
var file_name : String = "%s.tres" % [ prefix ]
|
||||
ResourceSaver.save(file_name, new_material)
|
||||
resource_filesystem.update_file(file_name)
|
||||
return new_material
|
||||
# Export
|
||||
|
||||
return null
|
||||
func get_export_profiles() -> Array:
|
||||
return shader_model.exports.keys()
|
||||
|
||||
func _serialize(data: Dictionary) -> Dictionary:
|
||||
func get_export_extension(profile : String) -> String:
|
||||
return shader_model.exports[profile].export_extension
|
||||
|
||||
func get_export_path(profile : String) -> String:
|
||||
if export_paths.has(profile):
|
||||
return export_paths[profile]
|
||||
return ""
|
||||
|
||||
func subst_string(s : String, export_context : Dictionary) -> String:
|
||||
var modified : bool = true
|
||||
while modified:
|
||||
modified = false
|
||||
for k in export_context.keys():
|
||||
var new_s = s.replace(k, export_context[k])
|
||||
if new_s != s:
|
||||
s = new_s
|
||||
modified = true
|
||||
while (true):
|
||||
var search_string = "$(expr:"
|
||||
var position = s.find(search_string)
|
||||
if position == -1:
|
||||
break
|
||||
var parenthesis_level = 0
|
||||
var expr_begin = position+search_string.length()
|
||||
for i in range(expr_begin, s.length()):
|
||||
if s[i] == '(':
|
||||
parenthesis_level += 1
|
||||
elif s[i] == ')':
|
||||
if parenthesis_level == 0:
|
||||
var expression = s.substr(expr_begin, i-expr_begin)
|
||||
var expr = Expression.new()
|
||||
var error = expr.parse(expression, [])
|
||||
if error == OK:
|
||||
s = s.replace(s.substr(position, i+1-position), str(expr.execute()))
|
||||
else:
|
||||
s = s.replace(s.substr(position, i+1-position), "EXPRESSION ERROR ("+expression+")")
|
||||
break
|
||||
parenthesis_level -= 1
|
||||
return s
|
||||
|
||||
func create_file_from_template(template : String, file_name : String, export_context : Dictionary) -> bool:
|
||||
var in_file = File.new()
|
||||
var out_file = File.new()
|
||||
if in_file.open(mm_loader.STD_GENDEF_PATH+"/"+template, File.READ) != OK:
|
||||
if in_file.open(OS.get_executable_path().get_base_dir()+"/generators/"+template, File.READ) != OK:
|
||||
print("Cannot find template file "+template)
|
||||
return false
|
||||
Directory.new().remove(file_name)
|
||||
if out_file.open(file_name, File.WRITE) != OK:
|
||||
print("Cannot write file '"+file_name+"' ("+str(out_file.get_error())+")")
|
||||
return false
|
||||
var skip_state : Array = [ false ]
|
||||
while ! in_file.eof_reached():
|
||||
var l = in_file.get_line()
|
||||
if l.left(4) == "$if ":
|
||||
var condition = subst_string(l.right(4), export_context)
|
||||
var expr = Expression.new()
|
||||
var error = expr.parse(condition, [])
|
||||
if error != OK:
|
||||
print("Error in expression "+condition+": "+expr.get_error_text())
|
||||
continue
|
||||
skip_state.push_back(!expr.execute())
|
||||
elif l.left(3) == "$fi":
|
||||
skip_state.pop_back()
|
||||
elif l.left(5) == "$else":
|
||||
skip_state.push_back(!skip_state.pop_back())
|
||||
elif ! skip_state.back():
|
||||
out_file.store_line(subst_string(l, export_context))
|
||||
return true
|
||||
|
||||
func export_material(prefix : String, profile : String, size : int = 0) -> void:
|
||||
if size == 0:
|
||||
size = get_image_size()
|
||||
export_paths[profile] = prefix
|
||||
var export_context : Dictionary = {
|
||||
"$(path_prefix)":prefix,
|
||||
"$(file_prefix)":prefix.get_file()
|
||||
}
|
||||
for i in range(shader_model.inputs.size()):
|
||||
var input = shader_model.inputs[i]
|
||||
export_context["$(connected:"+input.name+")"] = "true" if get_source(i) != null else "false"
|
||||
for p in shader_model.parameters:
|
||||
var value = p.default
|
||||
if parameters.has(p.name):
|
||||
value = parameters[p.name]
|
||||
match p.type:
|
||||
"float", "size":
|
||||
export_context["$(param:"+p.name+")"] = str(value)
|
||||
"color":
|
||||
export_context["$(param:"+p.name+".r)"] = str(value.r)
|
||||
export_context["$(param:"+p.name+".g)"] = str(value.g)
|
||||
export_context["$(param:"+p.name+".b)"] = str(value.b)
|
||||
export_context["$(param:"+p.name+".a)"] = str(value.a)
|
||||
_:
|
||||
print(p.type+" not supported in material")
|
||||
if shader_model.exports[profile].has("uids"):
|
||||
for i in range(shader_model.exports[profile].uids):
|
||||
var uid : String
|
||||
var r = []
|
||||
for k in range(16):
|
||||
r.append(randi() & 255)
|
||||
r[6] = (r[6] & 0x0f) | 0x40
|
||||
r[8] = (r[8] & 0x3f) | 0x80
|
||||
for k in range(16):
|
||||
uid += '%02x' % r[k]
|
||||
export_context["$(uid:"+str(i)+")"] = uid
|
||||
for f in shader_model.exports[profile].files:
|
||||
if f.has("conditions"):
|
||||
var condition = subst_string(f.conditions, export_context)
|
||||
var expr = Expression.new()
|
||||
var error = expr.parse(condition, [])
|
||||
if error != OK:
|
||||
print("Error in expression: "+expr.get_error_text())
|
||||
continue
|
||||
if !expr.execute():
|
||||
continue
|
||||
match f.type:
|
||||
"texture":
|
||||
var file_name = subst_string(f.file_name, export_context)
|
||||
var result = render(f.output, size)
|
||||
while result is GDScriptFunctionState:
|
||||
result = yield(result, "completed")
|
||||
result.save_to_file(file_name)
|
||||
result.release()
|
||||
"template":
|
||||
var file_export_context = export_context.duplicate()
|
||||
if f.has("file_params"):
|
||||
for p in f.file_params.keys():
|
||||
file_export_context["$(file_param:"+p+")"] = f.file_params[p]
|
||||
var file_name = subst_string(f.file_name, export_context)
|
||||
create_file_from_template(f.template, file_name, file_export_context)
|
||||
|
||||
func _serialize_data(data: Dictionary) -> Dictionary:
|
||||
data = ._serialize_data(data)
|
||||
data.export_paths = export_paths
|
||||
return data
|
||||
|
||||
func _deserialize(data : Dictionary) -> void:
|
||||
._deserialize(data)
|
||||
if data.has("export_paths"):
|
||||
export_paths = data.export_paths.duplicate()
|
||||
|
@ -157,6 +157,10 @@ func replace_variable(string : String, variable : String, value : String) -> Str
|
||||
break
|
||||
new_string += string.left(pos)
|
||||
string = string.right(pos)
|
||||
if string.length() > keyword_size and is_word_letter(string[keyword_size]):
|
||||
new_string += string.left(keyword_size)
|
||||
string = string.right(keyword_size)
|
||||
continue
|
||||
if string.empty() or !is_word_letter(string[0]):
|
||||
new_string += value
|
||||
else:
|
||||
|
@ -6,17 +6,17 @@ var types : Dictionary = {}
|
||||
|
||||
func _ready():
|
||||
var file = File.new()
|
||||
if file.open("res://addons/material_maker/nodes/io_types.mmt", File.READ) != OK:
|
||||
print("Cannot read types")
|
||||
return false
|
||||
var type_list = parse_json(file.get_as_text())
|
||||
file.close()
|
||||
for t in type_list:
|
||||
if t.has("label"):
|
||||
type_names.push_back(t.name)
|
||||
var c = t.color
|
||||
t.color = Color(c.r, c.g, c.b, c.a)
|
||||
if file.open("res://addons/material_maker/nodes/preview_"+t.name+".shader", File.READ) == OK:
|
||||
t.preview = file.get_as_text()
|
||||
for p in mm_loader.get_nodes_paths():
|
||||
if file.open(p+"/io_types.mmt", File.READ) == OK:
|
||||
var type_list = parse_json(file.get_as_text())
|
||||
file.close()
|
||||
types[t.name] = t
|
||||
for t in type_list:
|
||||
if t.has("label"):
|
||||
type_names.push_back(t.name)
|
||||
var c = t.color
|
||||
t.color = Color(c.r, c.g, c.b, c.a)
|
||||
if file.open(p+"/preview_"+t.name+".shader", File.READ) == OK:
|
||||
t.preview = file.get_as_text()
|
||||
file.close()
|
||||
types[t.name] = t
|
||||
break
|
||||
|
@ -8,9 +8,12 @@ var predefined_generators = {}
|
||||
func _ready()-> void:
|
||||
update_predefined_generators()
|
||||
|
||||
func get_nodes_paths() -> Array:
|
||||
return [ STD_GENDEF_PATH, OS.get_executable_path().get_base_dir()+"/nodes" ]
|
||||
|
||||
func update_predefined_generators()-> void:
|
||||
predefined_generators = {}
|
||||
for path in [ STD_GENDEF_PATH, OS.get_executable_path().get_base_dir()+"/generators" ]:
|
||||
for path in get_nodes_paths():
|
||||
var dir = Directory.new()
|
||||
if dir.open(path) == OK:
|
||||
dir.list_dir_begin()
|
||||
@ -24,7 +27,7 @@ func update_predefined_generators()-> void:
|
||||
file_name = dir.get_next()
|
||||
|
||||
func generator_name_from_path(path : String) -> String:
|
||||
for p in [ STD_GENDEF_PATH, OS.get_executable_path().get_base_dir()+"/generators" ]:
|
||||
for p in get_nodes_paths():
|
||||
print(p)
|
||||
print(path.get_base_dir())
|
||||
return path.get_basename().get_file()
|
||||
@ -56,6 +59,8 @@ func add_to_gen_graph(gen_graph, generators, connections) -> Dictionary:
|
||||
|
||||
func create_gen(data) -> MMGenBase:
|
||||
var guess = [
|
||||
{ keyword="export", type=MMGenMaterial },
|
||||
{ keyword="connections", type=MMGenGraph },
|
||||
{ keyword="connections", type=MMGenGraph },
|
||||
{ keyword="nodes", type=MMGenGraph },
|
||||
{ keyword="shader_model", type=MMGenShader },
|
||||
@ -65,7 +70,7 @@ func create_gen(data) -> MMGenBase:
|
||||
{ keyword="widgets", type=MMGenRemote }
|
||||
]
|
||||
var types = {
|
||||
material = MMGenMaterial,
|
||||
material_export = MMGenMaterial,
|
||||
buffer = MMGenBuffer,
|
||||
image = MMGenImage,
|
||||
ios = MMGenIOs,
|
||||
@ -99,7 +104,7 @@ func create_gen(data) -> MMGenBase:
|
||||
func get_generator_list() -> Array:
|
||||
var rv = []
|
||||
var dir : Directory = Directory.new()
|
||||
for p in [ STD_GENDEF_PATH, OS.get_executable_path().get_base_dir()+"/generators" ]:
|
||||
for p in get_nodes_paths():
|
||||
dir.open(p)
|
||||
dir.list_dir_begin(true)
|
||||
while true:
|
||||
|
@ -46,20 +46,26 @@ func get_visible_name() -> String:
|
||||
return "Material Maker Importer"
|
||||
|
||||
func import(source_file: String, save_path: String, options: Dictionary, platform_variants: Array, gen_files: Array) -> int:
|
||||
var filename = save_path + "." + get_save_extension()
|
||||
var material = null
|
||||
if options.render:
|
||||
material = plugin.generate_material(source_file)
|
||||
while material is GDScriptFunctionState:
|
||||
material = yield(material, "completed")
|
||||
var gen = mm_loader.load_gen(source_file)
|
||||
if gen != null:
|
||||
plugin.add_child(gen)
|
||||
for c in gen.get_children():
|
||||
if c.has_method("get_export_profiles"):
|
||||
var result = c.export_material(source_file.get_basename(), "Godot")
|
||||
while result is GDScriptFunctionState:
|
||||
result = yield(result, "completed")
|
||||
break
|
||||
gen.queue_free()
|
||||
else:
|
||||
var filename = save_path + "." + get_save_extension()
|
||||
material = SpatialMaterial.new()
|
||||
material.set_script(preload("res://addons/material_maker/import_plugin/ptex_spatial_material.gd"))
|
||||
var file : File = File.new()
|
||||
if file.open(source_file, File.READ) == OK:
|
||||
material.set_ptex_no_render(to_json(parse_json(file.get_as_text())))
|
||||
file.close()
|
||||
if material != null:
|
||||
material.uv1_scale = options.scale * Vector3(1.0, 1.0, 1.0)
|
||||
ResourceSaver.save(filename, material)
|
||||
return OK
|
||||
|
@ -23,6 +23,6 @@ func update_texture() -> void:
|
||||
var status = mm_material.render_textures()
|
||||
while status is GDScriptFunctionState:
|
||||
status = yield(status, "completed")
|
||||
mm_material.update_spatial_material(self)
|
||||
mm_material.update_material(self)
|
||||
mm_graph.queue_free()
|
||||
|
||||
|
52
addons/material_maker/nodes/godot.tres.tmpl
Normal file
52
addons/material_maker/nodes/godot.tres.tmpl
Normal file
@ -0,0 +1,52 @@
|
||||
[gd_resource type="SpatialMaterial" load_steps=5 format=2]
|
||||
|
||||
$if $(connected:albedo_tex)
|
||||
[ext_resource path="$(file_prefix)_albedo.png" type="Texture" id=1]
|
||||
$fi
|
||||
$if $(connected:ao_tex) or $(connected:roughness_tex) or $(connected:metallic_tex)
|
||||
[ext_resource path="$(file_prefix)_orm.png" type="Texture" id=2]
|
||||
$fi
|
||||
$if $(connected:normal_tex)
|
||||
[ext_resource path="$(file_prefix)_normal.png" type="Texture" id=3]
|
||||
$fi
|
||||
$if $(connected:depth_tex)
|
||||
[ext_resource path="$(file_prefix)_depth.png" type="Texture" id=4]
|
||||
$fi
|
||||
|
||||
[resource]
|
||||
albedo_color = Color($(param:albedo_color.r), $(param:albedo_color.g), $(param:albedo_color.b), $(param:albedo_color.a))
|
||||
$if $(connected:albedo_tex)
|
||||
albedo_texture = ExtResource( 1 )
|
||||
$fi
|
||||
metallic = $(param:metallic)
|
||||
$if $(connected:metallic_tex)
|
||||
metallic_texture = ExtResource( 2 )
|
||||
metallic_texture_channel = 2
|
||||
$fi
|
||||
roughness = $(param:roughness)
|
||||
$if $(connected:ao_tex) or $(connected:roughness_tex) or $(connected:metallic_tex)
|
||||
roughness_texture = ExtResource( 2 )
|
||||
roughness_texture_channel = 1
|
||||
$fi
|
||||
$if $(connected:normal_tex)
|
||||
normal_enabled = true
|
||||
normal_scale = $(param:normal)
|
||||
normal_texture = ExtResource( 3 )
|
||||
$fi
|
||||
$if $(connected:ao_tex)
|
||||
ao_enabled = true
|
||||
ao_light_affect = $(param:ao)
|
||||
ao_texture = ExtResource( 2 )
|
||||
ao_on_uv2 = false
|
||||
ao_texture_channel = 0
|
||||
$fi
|
||||
$if $(connected:depth_tex)
|
||||
depth_enabled = true
|
||||
depth_scale = $(expr:0.2*$(param:depth_scale))
|
||||
depth_deep_parallax = true
|
||||
depth_min_layers = 8
|
||||
depth_max_layers = 32
|
||||
depth_flip_tangent = false
|
||||
depth_flip_binormal = false
|
||||
depth_texture = ExtResource( 4 )
|
||||
$fi
|
427
addons/material_maker/nodes/material.mmg
Normal file
427
addons/material_maker/nodes/material.mmg
Normal file
@ -0,0 +1,427 @@
|
||||
{
|
||||
"name": "material",
|
||||
"node_position": {
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"parameters": {
|
||||
"albedo_color": {
|
||||
"a": 1,
|
||||
"b": 1,
|
||||
"g": 1,
|
||||
"r": 1,
|
||||
"type": "Color"
|
||||
},
|
||||
"ao": 1,
|
||||
"depth_scale": 0.5,
|
||||
"emission": 1,
|
||||
"metallic": 1,
|
||||
"normal": 1,
|
||||
"roughness": 1,
|
||||
"size": 11,
|
||||
"sss": 0
|
||||
},
|
||||
"export": {
|
||||
},
|
||||
"shader_model": {
|
||||
"code": "",
|
||||
"global": "",
|
||||
"inputs": [
|
||||
{
|
||||
"default": "vec3(1.0)",
|
||||
"label": "",
|
||||
"name": "albedo_tex",
|
||||
"type": "rgb"
|
||||
},
|
||||
{
|
||||
"default": "1.0",
|
||||
"label": "",
|
||||
"name": "metallic_tex",
|
||||
"type": "f"
|
||||
},
|
||||
{
|
||||
"default": "1.0",
|
||||
"label": "",
|
||||
"name": "roughness_tex",
|
||||
"type": "f"
|
||||
},
|
||||
{
|
||||
"default": "vec3(0.0)",
|
||||
"label": "",
|
||||
"name": "emission_tex",
|
||||
"type": "rgb"
|
||||
},
|
||||
{
|
||||
"default": "vec3(0.5)",
|
||||
"label": "",
|
||||
"name": "normal_tex",
|
||||
"type": "rgb"
|
||||
},
|
||||
{
|
||||
"default": "1.0",
|
||||
"label": "",
|
||||
"name": "ao_tex",
|
||||
"type": "f"
|
||||
},
|
||||
{
|
||||
"default": "0.0",
|
||||
"label": "",
|
||||
"name": "depth_tex",
|
||||
"type": "f"
|
||||
},
|
||||
{
|
||||
"default": "0.0",
|
||||
"label": "",
|
||||
"name": "sss_tex",
|
||||
"type": "f"
|
||||
}
|
||||
],
|
||||
"instance": "",
|
||||
"name": "Material",
|
||||
"outputs": [
|
||||
{
|
||||
"desc":"0: albedo",
|
||||
"rgb": "$albedo_tex($uv)",
|
||||
"type": "rgb"
|
||||
},
|
||||
{
|
||||
"desc":"1: ambient occlusion, roughness, metallic",
|
||||
"rgb": "vec3($ao_tex($uv), $roughness_tex($uv), $metallic_tex($uv))",
|
||||
"type": "rgb"
|
||||
},
|
||||
{
|
||||
"desc":"2: emission",
|
||||
"rgb": "$emission_tex($uv)",
|
||||
"type": "rgb"
|
||||
},
|
||||
{
|
||||
"desc":"3: normal map for Godot",
|
||||
"rgb": "$normal_tex($uv)*vec3(-1.0, 1.0, 1.0)+vec3(1.0, 0.0, 0.0)",
|
||||
"type": "rgb"
|
||||
},
|
||||
{
|
||||
"desc":"4: normal map for Godot",
|
||||
"f": "$depth_tex($uv)",
|
||||
"type": "f"
|
||||
},
|
||||
{
|
||||
"desc":"5: sub surface scattering",
|
||||
"f": "$sss_tex($uv)",
|
||||
"type": "f"
|
||||
},
|
||||
{
|
||||
"desc":"6: unity metallic/smoothness",
|
||||
"rgba": "vec4(vec3($metallic_tex($uv)), 1.0-$roughness_tex($uv))",
|
||||
"type": "rgba"
|
||||
},
|
||||
{
|
||||
"desc":"7: unity normal",
|
||||
"rgb": "$normal_tex($uv)*vec3(-1.0, 1.0, -1.0)+vec3(1.0, 0.0, 1.0)",
|
||||
"type": "rgb"
|
||||
},
|
||||
{
|
||||
"desc":"8: unity height",
|
||||
"f": "1.0-$depth_tex($uv)",
|
||||
"type": "f"
|
||||
},
|
||||
{
|
||||
"desc":"9: unity occlusion",
|
||||
"f": "$ao_tex($uv)",
|
||||
"type": "f"
|
||||
},
|
||||
{
|
||||
"desc":"10: unreal normal",
|
||||
"rgb": "$normal_tex($uv)*vec3(-1.0)+vec3(1.0)",
|
||||
"type": "rgb"
|
||||
}
|
||||
],
|
||||
"exports": {
|
||||
"Godot": {
|
||||
"export_extension":"tres",
|
||||
"files": [
|
||||
{
|
||||
"type":"texture",
|
||||
"file_name":"$(path_prefix)_albedo.png",
|
||||
"output":0,
|
||||
"conditions":"$(connected:albedo_tex)"
|
||||
},
|
||||
{
|
||||
"type":"texture",
|
||||
"file_name":"$(path_prefix)_orm.png",
|
||||
"output":1,
|
||||
"conditions":"$(connected:ao_tex) or $(connected:roughness_tex) or $(connected:metallic_tex)"
|
||||
},
|
||||
{
|
||||
"type":"texture",
|
||||
"file_name":"$(path_prefix)_emission.png",
|
||||
"output":2,
|
||||
"conditions":"$(connected:emission_tex)"
|
||||
},
|
||||
{
|
||||
"type":"texture",
|
||||
"file_name":"$(path_prefix)_normal.png",
|
||||
"output":3,
|
||||
"conditions":"$(connected:normal_tex)"
|
||||
},
|
||||
{
|
||||
"type":"texture",
|
||||
"file_name":"$(path_prefix)_depth.png",
|
||||
"output":4,
|
||||
"conditions":"$(connected:depth_tex)"
|
||||
},
|
||||
{
|
||||
"type":"texture",
|
||||
"file_name":"$(path_prefix)_sss.png",
|
||||
"output":5,
|
||||
"conditions":"$(connected:sss_tex)"
|
||||
},
|
||||
{
|
||||
"type":"template",
|
||||
"file_name":"$(path_prefix).tres",
|
||||
"template":"godot.tres.tmpl"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Unity": {
|
||||
"export_extension":"mat",
|
||||
"uids":6,
|
||||
"files": [
|
||||
{
|
||||
"type":"texture",
|
||||
"file_name":"$(path_prefix)_albedo.png",
|
||||
"output":0,
|
||||
"conditions":"$(connected:albedo_tex)"
|
||||
},
|
||||
{
|
||||
"type":"template",
|
||||
"file_name":"$(path_prefix)_albedo.png.meta",
|
||||
"template":"unity.png.meta.tmpl",
|
||||
"file_params": {
|
||||
"uid":"$(uid:0)",
|
||||
"srgb":"1",
|
||||
"normal":"0"
|
||||
},
|
||||
"conditions":"$(connected:albedo_tex)"
|
||||
},
|
||||
{
|
||||
"type":"texture",
|
||||
"file_name":"$(path_prefix)_metal_smoothness.png",
|
||||
"output":6,
|
||||
"conditions":"$(connected:roughness_tex) or $(connected:metallic_tex)"
|
||||
},
|
||||
{
|
||||
"type":"template",
|
||||
"file_name":"$(path_prefix)_metal_smoothness.png.meta",
|
||||
"template":"unity.png.meta.tmpl",
|
||||
"file_params": {
|
||||
"uid":"$(uid:1)",
|
||||
"srgb":"1",
|
||||
"normal":"0"
|
||||
},
|
||||
"conditions":"$(connected:roughness_tex) or $(connected:metallic_tex)"
|
||||
},
|
||||
{
|
||||
"type":"texture",
|
||||
"file_name":"$(path_prefix)_normal.png",
|
||||
"output":7,
|
||||
"conditions":"$(connected:normal_tex)"
|
||||
},
|
||||
{
|
||||
"type":"template",
|
||||
"file_name":"$(path_prefix)_normal.png.meta",
|
||||
"template":"unity.png.meta.tmpl",
|
||||
"file_params": {
|
||||
"uid":"$(uid:2)",
|
||||
"srgb":"0",
|
||||
"normal":"1"
|
||||
},
|
||||
"conditions":"$(connected:normal_tex)"
|
||||
},
|
||||
{
|
||||
"type":"texture",
|
||||
"file_name":"$(path_prefix)_height.png",
|
||||
"output":8,
|
||||
"conditions":"$(connected:depth_tex)"
|
||||
},
|
||||
{
|
||||
"type":"template",
|
||||
"file_name":"$(path_prefix)_height.png.meta",
|
||||
"template":"unity.png.meta.tmpl",
|
||||
"file_params": {
|
||||
"uid":"$(uid:3)",
|
||||
"srgb":"1",
|
||||
"normal":"0"
|
||||
},
|
||||
"conditions":"$(connected:depth_tex)"
|
||||
},
|
||||
{
|
||||
"type":"texture",
|
||||
"file_name":"$(path_prefix)_occlusion.png",
|
||||
"output":9,
|
||||
"conditions":"$(connected:ao_tex)"
|
||||
},
|
||||
{
|
||||
"type":"template",
|
||||
"file_name":"$(path_prefix)_occlusion.png.meta",
|
||||
"template":"unity.png.meta.tmpl",
|
||||
"file_params": {
|
||||
"uid":"$(uid:4)",
|
||||
"srgb":"1",
|
||||
"normal":"0"
|
||||
},
|
||||
"conditions":"$(connected:ao_tex)"
|
||||
},
|
||||
{
|
||||
"type":"texture",
|
||||
"file_name":"$(path_prefix)_emission.png",
|
||||
"output":2,
|
||||
"conditions":"$(connected:emission_tex)"
|
||||
},
|
||||
{
|
||||
"type":"template",
|
||||
"file_name":"$(path_prefix)_emission.png.meta",
|
||||
"template":"unity.png.meta.tmpl",
|
||||
"file_params": {
|
||||
"uid":"$(uid:5)",
|
||||
"srgb":"1",
|
||||
"normal":"0"
|
||||
},
|
||||
"conditions":"$(connected:emission_tex)"
|
||||
},
|
||||
{
|
||||
"type":"template",
|
||||
"file_name":"$(path_prefix).mat",
|
||||
"template":"unity.mat.tmpl"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Unreal": {
|
||||
"export_extension":"tres",
|
||||
"files": [
|
||||
{
|
||||
"type":"texture",
|
||||
"file_name":"$(path_prefix)_albedo.png",
|
||||
"output":0,
|
||||
"conditions":"$(connected:albedo_tex)"
|
||||
},
|
||||
{
|
||||
"type":"texture",
|
||||
"file_name":"$(path_prefix)_orm.png",
|
||||
"output":1,
|
||||
"conditions":"$(connected:ao_tex) or $(connected:roughness_tex) or $(connected:metallic_tex)"
|
||||
},
|
||||
{
|
||||
"type":"texture",
|
||||
"file_name":"$(path_prefix)_emission.png",
|
||||
"output":2,
|
||||
"conditions":"$(connected:emission_tex)"
|
||||
},
|
||||
{
|
||||
"type":"texture",
|
||||
"file_name":"$(path_prefix)_normal.png",
|
||||
"output":10,
|
||||
"conditions":"$(connected:normal_tex)"
|
||||
},
|
||||
{
|
||||
"type":"texture",
|
||||
"file_name":"$(path_prefix)_height.png",
|
||||
"output":8,
|
||||
"conditions":"$(connected:depth_tex)"
|
||||
}
|
||||
]
|
||||
},
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"default": {
|
||||
"a": 1,
|
||||
"b": 1,
|
||||
"g": 1,
|
||||
"r": 1
|
||||
},
|
||||
"label": "Albedo",
|
||||
"name": "albedo_color",
|
||||
"type": "color"
|
||||
},
|
||||
{
|
||||
"control": "None",
|
||||
"default": 1,
|
||||
"label": "Metallic",
|
||||
"max": 1,
|
||||
"min": 0,
|
||||
"name": "metallic",
|
||||
"step": 0.01,
|
||||
"type": "float"
|
||||
},
|
||||
{
|
||||
"control": "None",
|
||||
"default": 1,
|
||||
"label": "Roughness",
|
||||
"max": 1,
|
||||
"min": 0,
|
||||
"name": "roughness",
|
||||
"step": 0.01,
|
||||
"type": "float"
|
||||
},
|
||||
{
|
||||
"control": "None",
|
||||
"default": 1,
|
||||
"label": "Emission",
|
||||
"max": 1,
|
||||
"min": 0,
|
||||
"name": "emission_energy",
|
||||
"step": 0.01,
|
||||
"type": "float"
|
||||
},
|
||||
{
|
||||
"control": "None",
|
||||
"default": 1,
|
||||
"label": "Normal",
|
||||
"max": 10,
|
||||
"min": 0,
|
||||
"name": "normal",
|
||||
"step": 0.01,
|
||||
"type": "float"
|
||||
},
|
||||
{
|
||||
"control": "None",
|
||||
"default": 1,
|
||||
"label": "Ambient occlusion",
|
||||
"max": 1,
|
||||
"min": 0,
|
||||
"name": "ao",
|
||||
"step": 0.01,
|
||||
"type": "float"
|
||||
},
|
||||
{
|
||||
"control": "None",
|
||||
"default": 0.5,
|
||||
"label": "Depth",
|
||||
"max": 1,
|
||||
"min": 0,
|
||||
"name": "depth_scale",
|
||||
"step": 0.01,
|
||||
"type": "float"
|
||||
},
|
||||
{
|
||||
"control": "None",
|
||||
"default": 0,
|
||||
"label": "Subsurf. scatter.",
|
||||
"max": 1,
|
||||
"min": 0,
|
||||
"name": "sss",
|
||||
"step": 0.01,
|
||||
"type": "float"
|
||||
},
|
||||
{
|
||||
"default": 11,
|
||||
"first": 6,
|
||||
"label": "Size",
|
||||
"last": 12,
|
||||
"name": "size",
|
||||
"type": "size"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "material_export"
|
||||
}
|
97
addons/material_maker/nodes/unity.mat.tmpl
Normal file
97
addons/material_maker/nodes/unity.mat.tmpl
Normal file
@ -0,0 +1,97 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: test
|
||||
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_ShaderKeywords:$(expr:" _METALLICGLOSSMAP" if $(connected:roughness_tex) or $(connected:metallic_tex) else "")$(expr:" _NORMALMAP" if $(connected:normal_tex) else "")$(expr:" _PARALLAXMAP" if $(connected:depth_tex) else "")
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
disabledShaderPasses: []
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _BumpMap:
|
||||
$if $(connected:normal_tex)
|
||||
m_Texture: {fileID: 2800000, guid: $(uid:2), type: 3}
|
||||
$else
|
||||
m_Texture: {fileID: 0}
|
||||
$fi
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailAlbedoMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailMask:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailNormalMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _EmissionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
$if $(connected:albedo_tex)
|
||||
m_Texture: {fileID: 2800000, guid: $(uid:0), type: 3}
|
||||
$else
|
||||
m_Texture: {fileID: 0}
|
||||
$fi
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
$if $(connected:roughness_tex) or $(connected:metallic_tex)
|
||||
m_Texture: {fileID: 2800000, guid: $(uid:1), type: 3}
|
||||
$else
|
||||
m_Texture: {fileID: 0}
|
||||
$fi
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OcclusionMap:
|
||||
$if $(connected:ao_tex)
|
||||
m_Texture: {fileID: 2800000, guid: $(uid:4), type: 3}
|
||||
$else
|
||||
m_Texture: {fileID: 0}
|
||||
$fi
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ParallaxMap:
|
||||
$if $(connected:depth_tex)
|
||||
m_Texture: {fileID: 2800000, guid: $(uid:3), type: 3}
|
||||
$else
|
||||
m_Texture: {fileID: 0}
|
||||
$fi
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Floats:
|
||||
- _BumpScale: 1
|
||||
- _Cutoff: 0.5
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 0
|
||||
- _GlossMapScale: 1
|
||||
- _Glossiness: 0.5
|
||||
- _GlossyReflections: 1
|
||||
- _Metallic: 0
|
||||
- _Mode: 0
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.02
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SrcBlend: 1
|
||||
- _UVSec: 0
|
||||
- _ZWrite: 1
|
||||
m_Colors:
|
||||
- _Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
91
addons/material_maker/nodes/unity.png.meta.tmpl
Normal file
91
addons/material_maker/nodes/unity.png.meta.tmpl
Normal file
@ -0,0 +1,91 @@
|
||||
fileFormatVersion: 2
|
||||
guid: $(file_param:uid)
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 10
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: $(file_param:srgb)
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -100
|
||||
wrapU: -1
|
||||
wrapV: -1
|
||||
wrapW: -1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: $(file_param:normal)
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,7 +1,7 @@
|
||||
[plugin]
|
||||
|
||||
name="MaterialMaker"
|
||||
description="Procedural Material creation tool"
|
||||
name="Material Maker"
|
||||
description="Import plugin for Material Maker"
|
||||
author="RodZilla"
|
||||
version="0.6"
|
||||
version="0.9"
|
||||
script="plugin.gd"
|
||||
|
@ -11,16 +11,3 @@ func _exit_tree() -> void:
|
||||
if importer != null:
|
||||
remove_import_plugin(importer)
|
||||
importer = null
|
||||
|
||||
func generate_material(ptex_filename: String) -> Material:
|
||||
var generator = mm_loader.load_gen(ptex_filename)
|
||||
add_child(generator)
|
||||
if generator.has_node("Material"):
|
||||
var gen_material = generator.get_node("Material")
|
||||
if gen_material != null:
|
||||
var return_value = gen_material.render_textures()
|
||||
while return_value is GDScriptFunctionState:
|
||||
return_value = yield(return_value, "completed")
|
||||
var prefix = ptex_filename.left(ptex_filename.rfind("."))
|
||||
return gen_material.export_textures(prefix, get_editor_interface())
|
||||
return null
|
||||
|
File diff suppressed because one or more lines are too long
18
material_maker/doc/command_line.rst
Normal file
18
material_maker/doc/command_line.rst
Normal file
@ -0,0 +1,18 @@
|
||||
Command line arguments
|
||||
======================
|
||||
|
||||
When launched with no command line argument, Material Maker will start with an empty project.
|
||||
|
||||
When launched with the path of a .ptex file as command line argument, Material Maker will
|
||||
start with this project file. Material Maker can thus be associated to files with .ptex
|
||||
extension so double-clicking on them will directly open them.
|
||||
|
||||
Material Maker can also be used to export several .ptex file with the following command line:
|
||||
|
||||
material_maker --export -t <engine> -o <output_path> <input_files>
|
||||
|
||||
Where:
|
||||
|
||||
* **engine** is the target engine (Godot, Unity or Unreal)
|
||||
* **output_path** is the path where files will be generated
|
||||
* **input_files** is the list of input files (wildcards are accepted)
|
@ -24,7 +24,7 @@ copyright = '2018-2020, Rodz Labs'
|
||||
author = 'Rodz Labs'
|
||||
|
||||
# The short X.Y version
|
||||
version = '0.8'
|
||||
version = '0.9'
|
||||
# The full version, including alpha/beta/rc tags
|
||||
release = ''
|
||||
|
||||
|
59
material_maker/doc/export.rst
Normal file
59
material_maker/doc/export.rst
Normal file
@ -0,0 +1,59 @@
|
||||
.. _export-section:
|
||||
|
||||
Exporting Materials
|
||||
===================
|
||||
|
||||
When exporting a material, using either the Export submenu or the command line arguments,
|
||||
Material Maker generates PNG image files for all elements of the material as well as
|
||||
specific files for the target game engine.
|
||||
|
||||
In all cases, the generated PNG files (and especially the normal map) is generated in the
|
||||
correct format.
|
||||
|
||||
Godot game engine
|
||||
-----------------
|
||||
|
||||
When exporting for the Godot game engine, Material Maker will generate a .tres file that
|
||||
describes a fully configured SpatialMaterial.
|
||||
|
||||
Note that exporting for Godot is not necessary if you use the Material maker addon, that
|
||||
provides an import plugin. This import plugin can either generate a precomputed material,
|
||||
or a material that will be rendered at runtime.
|
||||
|
||||
Unity game engine
|
||||
-----------------
|
||||
|
||||
When exporting for the Unity game engine, Material Maker will generate a .mat file that
|
||||
describes a fully configured material. It is thus possible to export materials directly
|
||||
into one of your project assets directory, and Unity will automatically detect the newly
|
||||
exported materials.
|
||||
|
||||
Unreal game engine
|
||||
------------------
|
||||
|
||||
When exporting for the Unreal game engine, Material Maker will only generate PNG image
|
||||
files, and it is necessary to create the material in Unreal.
|
||||
|
||||
To create a minimal material:
|
||||
|
||||
* import all PNG files into unreal
|
||||
* create a new material using the **Add new -> Material** menu
|
||||
* open the new material to edit it
|
||||
* drag and drop all textures into the material graph to create a Texture Sample node
|
||||
for each texture
|
||||
* connect the RGB output of the albedo *Texture Sample* node to the *Base Color* input
|
||||
of the material node
|
||||
* connect the R output of the ORM *Texture Sample* node to the *Ambient Occlusion* input
|
||||
of the material node
|
||||
* connect the G output of the ORM *Texture Sample* node to the *Roughness* input
|
||||
of the material node
|
||||
* connect the B output of the ORM *Texture Sample* node to the *Metallic* input
|
||||
of the material node
|
||||
* connect the RGB output of the normal *Texture Sample* node to the *Normal* input
|
||||
of the material node
|
||||
|
||||
More complex materials with support for emission textures, depth maps, texture
|
||||
coordinate scaling...
|
||||
|
||||
.. image:: images/unreal_export.png
|
||||
:align: center
|
BIN
material_maker/doc/images/unreal_export.png
Normal file
BIN
material_maker/doc/images/unreal_export.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 234 KiB |
@ -8,3 +8,5 @@ Material Maker User Manual
|
||||
user_interface
|
||||
nodes
|
||||
base_library
|
||||
export
|
||||
command_line
|
||||
|
@ -21,17 +21,29 @@ Parameters
|
||||
|
||||
The **Normal map** node has the following parameters:
|
||||
|
||||
* the *format* of the normal map (default, OpenGL or DirectX)
|
||||
* the *format* of the normal map (default, OpenGL or DirectX). The format should
|
||||
always be set to "default" when connected to the Normal input of a Material node.
|
||||
The correct normal map format for the target game engine will be generated when
|
||||
the material is exported.
|
||||
|
||||
* the *size* of the normal map
|
||||
|
||||
* the *strength* of the normal map effect
|
||||
|
||||
* the *buffer* parameter decides if the input must be stored in a buffer before
|
||||
generating the normal map. Using a buffer is faster but can create artifacts
|
||||
in the normal map, and disabling this option will generate more accurate normal
|
||||
maps. It is recommended to enable the buffer while editing a material and
|
||||
disable it before exporting.
|
||||
|
||||
Notes
|
||||
+++++
|
||||
|
||||
This node outputs an image that has a fixed size.
|
||||
|
||||
When using 3D Signed distance functions, it is recommended to use the normal map
|
||||
generated by the
|
||||
|
||||
Example images
|
||||
++++++++++++++
|
||||
|
||||
|
@ -224,10 +224,10 @@ The main menu bar is organized in 5 menus:
|
||||
File menu
|
||||
^^^^^^^^^
|
||||
|
||||
* *New material* creates a new material and opens a tab in the right pane to edit it
|
||||
* *New material* creates a new material and opens a tab in the center pane to edit it
|
||||
|
||||
* *Load material* opens a file dialog to select a procedural material (.ptex) file. If
|
||||
a material file is selected, it will be open in a new tab in the right pane. If the current
|
||||
a material file is selected, it will be open in a new tab in the center pane. If the current
|
||||
tab contains an empty material (about material that only consists of a Material node), the
|
||||
material will be loaded into this tab.
|
||||
|
||||
@ -239,12 +239,10 @@ File menu
|
||||
* *Save all materials* saves all currently open materials. Materials that were already
|
||||
saved are ignored.
|
||||
|
||||
* *Export material* generates PNG image files for all elements of the material. File names are
|
||||
defined using the path of the **.ptex** material file and their role (albedo, emission...)
|
||||
in the material.
|
||||
The Ambient occlusion, roughness and metallic textures are saved into a single file whose
|
||||
suffix is **orm**.
|
||||
If the material contains **export** nodes, their textures will be exported as well.
|
||||
* the *Export* submenu can be used to export the current Material for Godot, Unity
|
||||
or Unreal. It will prompt for a file name and generate PNG files for all components
|
||||
of the material. Exporting to one of those engines is described in the
|
||||
:ref:`export-section` section.
|
||||
|
||||
* *Close material* closes the current material.
|
||||
|
||||
|
@ -72,24 +72,12 @@
|
||||
"to": "blend_0",
|
||||
"to_port": 1
|
||||
},
|
||||
{
|
||||
"from": "colorize_0",
|
||||
"from_port": 0,
|
||||
"to": "combine_0",
|
||||
"to_port": 1
|
||||
},
|
||||
{
|
||||
"from": "blend_0",
|
||||
"from_port": 0,
|
||||
"to": "colorize_2",
|
||||
"to_port": 0
|
||||
},
|
||||
{
|
||||
"from": "blend_0",
|
||||
"from_port": 0,
|
||||
"to": "combine_0",
|
||||
"to_port": 0
|
||||
},
|
||||
{
|
||||
"from": "colorize_2",
|
||||
"from_port": 0,
|
||||
@ -121,8 +109,8 @@
|
||||
{
|
||||
"name": "perlin_1",
|
||||
"node_position": {
|
||||
"x": -424,
|
||||
"y": 343.5
|
||||
"x": -635,
|
||||
"y": 341.5
|
||||
},
|
||||
"parameters": {
|
||||
"iterations": 3,
|
||||
@ -135,8 +123,8 @@
|
||||
{
|
||||
"name": "perlin_0",
|
||||
"node_position": {
|
||||
"x": -424,
|
||||
"y": 212.5
|
||||
"x": -635,
|
||||
"y": 210.5
|
||||
},
|
||||
"parameters": {
|
||||
"iterations": 3,
|
||||
@ -149,21 +137,20 @@
|
||||
{
|
||||
"name": "warp_0",
|
||||
"node_position": {
|
||||
"x": -180,
|
||||
"y": 317.5
|
||||
"x": -311,
|
||||
"y": 280.5
|
||||
},
|
||||
"parameters": {
|
||||
"amount": 0.1,
|
||||
"eps": 0.05,
|
||||
"epsilon": 0
|
||||
"eps": 0.05
|
||||
},
|
||||
"type": "warp"
|
||||
},
|
||||
{
|
||||
"name": "colorize_1",
|
||||
"node_position": {
|
||||
"x": -194,
|
||||
"y": 466.5
|
||||
"x": -340,
|
||||
"y": 402.5
|
||||
},
|
||||
"parameters": {
|
||||
"gradient": {
|
||||
@ -192,21 +179,20 @@
|
||||
{
|
||||
"name": "warp_1",
|
||||
"node_position": {
|
||||
"x": -31,
|
||||
"y": 349.5
|
||||
"x": -89,
|
||||
"y": 325.5
|
||||
},
|
||||
"parameters": {
|
||||
"amount": 0.1,
|
||||
"eps": 0.045,
|
||||
"epsilon": 0
|
||||
"eps": 0.045
|
||||
},
|
||||
"type": "warp"
|
||||
},
|
||||
{
|
||||
"name": "voronoi_0",
|
||||
"node_position": {
|
||||
"x": -437,
|
||||
"y": 484.5
|
||||
"x": -648,
|
||||
"y": 482.5
|
||||
},
|
||||
"parameters": {
|
||||
"intensity": 1,
|
||||
@ -221,8 +207,8 @@
|
||||
{
|
||||
"name": "blend_0",
|
||||
"node_position": {
|
||||
"x": 83,
|
||||
"y": 245.5
|
||||
"x": 101,
|
||||
"y": 250.5
|
||||
},
|
||||
"parameters": {
|
||||
"amount": 1,
|
||||
@ -230,29 +216,11 @@
|
||||
},
|
||||
"type": "blend"
|
||||
},
|
||||
{
|
||||
"name": "combine_0",
|
||||
"node_position": {
|
||||
"x": 515.35144,
|
||||
"y": -15.818176
|
||||
},
|
||||
"parameters": {
|
||||
"color": {
|
||||
"a": 1,
|
||||
"b": 1,
|
||||
"g": 1,
|
||||
"r": 1,
|
||||
"type": "Color"
|
||||
},
|
||||
"name": 0
|
||||
},
|
||||
"type": "combine"
|
||||
},
|
||||
{
|
||||
"name": "Material",
|
||||
"node_position": {
|
||||
"x": 544,
|
||||
"y": 79
|
||||
"x": 687,
|
||||
"y": 172
|
||||
},
|
||||
"parameters": {
|
||||
"albedo_color": {
|
||||
@ -267,7 +235,6 @@
|
||||
"emission_energy": 1,
|
||||
"metallic": 1,
|
||||
"normal_scale": 1,
|
||||
"resolution": 1,
|
||||
"roughness": 1,
|
||||
"size": 11,
|
||||
"subsurf_scatter_strength": 0
|
||||
@ -277,25 +244,46 @@
|
||||
{
|
||||
"name": "colorize_2",
|
||||
"node_position": {
|
||||
"x": 305.35144,
|
||||
"y": 76.181824
|
||||
"x": 407.35144,
|
||||
"y": 127.181824
|
||||
},
|
||||
"parameters": {
|
||||
"gradient": {
|
||||
"interpolation": 1,
|
||||
"interpolation": 2,
|
||||
"points": [
|
||||
{
|
||||
"a": 1,
|
||||
"b": 0.071126,
|
||||
"g": 0.34877,
|
||||
"pos": 0,
|
||||
"pos": 0.120364,
|
||||
"r": 0.59375
|
||||
},
|
||||
{
|
||||
"a": 1,
|
||||
"b": 0.013021,
|
||||
"g": 0.144043,
|
||||
"pos": 1,
|
||||
"pos": 0.263636,
|
||||
"r": 0.3125
|
||||
},
|
||||
{
|
||||
"a": 1,
|
||||
"b": 0.071126,
|
||||
"g": 0.34877,
|
||||
"pos": 0.402182,
|
||||
"r": 0.59375
|
||||
},
|
||||
{
|
||||
"a": 1,
|
||||
"b": 0.071126,
|
||||
"g": 0.34877,
|
||||
"pos": 0.663636,
|
||||
"r": 0.59375
|
||||
},
|
||||
{
|
||||
"a": 1,
|
||||
"b": 0.013021,
|
||||
"g": 0.144043,
|
||||
"pos": 0.893091,
|
||||
"r": 0.3125
|
||||
}
|
||||
],
|
||||
@ -307,25 +295,22 @@
|
||||
{
|
||||
"name": "normal_map_0",
|
||||
"node_position": {
|
||||
"x": 319,
|
||||
"y": 265.5
|
||||
"x": 431,
|
||||
"y": 423.5
|
||||
},
|
||||
"parameters": {
|
||||
"amount": 0.1,
|
||||
"param0": 11,
|
||||
"param1": 0.99,
|
||||
"param2": 0,
|
||||
"param3": 0,
|
||||
"param4": 1,
|
||||
"size": 5
|
||||
"param4": 1
|
||||
},
|
||||
"type": "normal_map"
|
||||
},
|
||||
{
|
||||
"name": "colorize_0",
|
||||
"node_position": {
|
||||
"x": 313,
|
||||
"y": 176.5
|
||||
"x": 423,
|
||||
"y": 306.5
|
||||
},
|
||||
"parameters": {
|
||||
"gradient": {
|
||||
|
@ -213,16 +213,25 @@ func create_nodes(data, position : Vector2 = Vector2(0, 0)) -> Array:
|
||||
func create_gen_from_type(gen_name) -> void:
|
||||
create_nodes({ type=gen_name, parameters={} }, scroll_offset+0.5*rect_size)
|
||||
|
||||
func load_file(filename) -> void:
|
||||
clear_material()
|
||||
top_generator = mm_loader.load_gen(filename)
|
||||
if top_generator != null:
|
||||
func load_file(filename) -> bool:
|
||||
var new_generator = mm_loader.load_gen(filename)
|
||||
if new_generator != null:
|
||||
clear_material()
|
||||
top_generator = new_generator
|
||||
add_child(top_generator)
|
||||
move_child(top_generator, 0)
|
||||
update_view(top_generator)
|
||||
center_view()
|
||||
set_save_path(filename)
|
||||
set_need_save(false)
|
||||
return true
|
||||
else:
|
||||
var dialog : AcceptDialog = AcceptDialog.new()
|
||||
add_child(dialog)
|
||||
dialog.window_title = "Load failed!"
|
||||
dialog.dialog_text = "Failed to load "+filename
|
||||
dialog.popup_centered()
|
||||
return false
|
||||
|
||||
func save_file(filename) -> void:
|
||||
var data = top_generator.serialize()
|
||||
@ -233,14 +242,16 @@ func save_file(filename) -> void:
|
||||
set_save_path(filename)
|
||||
set_need_save(false)
|
||||
|
||||
func export_textures() -> void:
|
||||
if save_path != null:
|
||||
var prefix = save_path.left(save_path.rfind("."))
|
||||
for g in top_generator.get_children():
|
||||
if g.has_method("render_textures"):
|
||||
g.render_textures()
|
||||
if g.has_method("export_textures"):
|
||||
g.export_textures(prefix, editor_interface)
|
||||
func get_material_node() -> MMGenMaterial:
|
||||
for g in top_generator.get_children():
|
||||
if g.has_method("get_export_profiles"):
|
||||
return g
|
||||
return null
|
||||
|
||||
func export_material(export_prefix, profile) -> void:
|
||||
for g in top_generator.get_children():
|
||||
if g.has_method("export_material"):
|
||||
g.export_material(export_prefix, profile)
|
||||
|
||||
# Cut / copy / paste / duplicate
|
||||
|
||||
|
@ -37,7 +37,8 @@ const MENU = [
|
||||
{ menu="File", command="save_material_as", shortcut="Control+Shift+S", description="Save material as..." },
|
||||
{ menu="File", command="save_all_materials", description="Save all materials..." },
|
||||
{ menu="File" },
|
||||
{ menu="File", command="export_material", shortcut="Control+E", description="Export material" },
|
||||
{ menu="File", submenu="export_material", description="Export material" },
|
||||
#{ menu="File", command="export_material", shortcut="Control+E", description="Export material" },
|
||||
{ menu="File" },
|
||||
{ menu="File", command="close_material", description="Close material" },
|
||||
{ menu="File", command="quit", shortcut="Control+Q", description="Quit" },
|
||||
@ -61,7 +62,7 @@ const MENU = [
|
||||
{ menu="Tools", command="add_to_user_library", description="Add selected node to user library" },
|
||||
{ menu="Tools", command="export_library", description="Export the nodes library" },
|
||||
|
||||
{ menu="Tools", command="generate_screenshots", description="Generate screenshots for the library nodes" },
|
||||
#{ menu="Tools", command="generate_screenshots", description="Generate screenshots for the library nodes" },
|
||||
|
||||
|
||||
|
||||
@ -150,6 +151,8 @@ func _ready() -> void:
|
||||
create_menu(menu, m.name)
|
||||
m.connect("about_to_show", self, "menu_about_to_show", [ m.name, menu ])
|
||||
new_material()
|
||||
|
||||
do_load_materials(OS.get_cmdline_args())
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if event.is_action_pressed("toggle_fullscreen"):
|
||||
@ -199,7 +202,6 @@ func create_menu(menu, menu_name) -> PopupMenu:
|
||||
|
||||
func create_menu_load_recent(menu) -> void:
|
||||
menu.clear()
|
||||
|
||||
if recent_files.empty():
|
||||
menu.add_item("No items found", 0)
|
||||
menu.set_item_disabled(0, true)
|
||||
@ -210,7 +212,8 @@ func create_menu_load_recent(menu) -> void:
|
||||
menu.connect("id_pressed", self, "_on_LoadRecent_id_pressed")
|
||||
|
||||
func _on_LoadRecent_id_pressed(id) -> void:
|
||||
do_load_material(recent_files[id])
|
||||
if !do_load_material(recent_files[id]):
|
||||
recent_files.remove(id)
|
||||
|
||||
func load_recents() -> void:
|
||||
var f = File.new()
|
||||
@ -233,6 +236,42 @@ func add_recent(path) -> void:
|
||||
f.store_string(to_json(recent_files))
|
||||
f.close()
|
||||
|
||||
|
||||
func create_menu_export_material(menu) -> void:
|
||||
menu.clear()
|
||||
var graph_edit : MMGraphEdit = get_current_graph_edit()
|
||||
if graph_edit != null:
|
||||
var material_node = graph_edit.get_material_node()
|
||||
for p in material_node.get_export_profiles():
|
||||
menu.add_item(p)
|
||||
if !menu.is_connected("id_pressed", self, "_on_ExportMaterial_id_pressed"):
|
||||
menu.connect("id_pressed", self, "_on_ExportMaterial_id_pressed")
|
||||
|
||||
func export_material(file_path : String, profile : String) -> void:
|
||||
var graph_edit : MMGraphEdit = get_current_graph_edit()
|
||||
if graph_edit == null:
|
||||
return
|
||||
var export_prefix = file_path.trim_suffix("."+file_path.get_extension())
|
||||
graph_edit.export_material(export_prefix, profile)
|
||||
|
||||
func _on_ExportMaterial_id_pressed(id) -> void:
|
||||
var graph_edit : MMGraphEdit = get_current_graph_edit()
|
||||
if graph_edit == null:
|
||||
return
|
||||
var material_node = graph_edit.get_material_node()
|
||||
if material_node == null:
|
||||
return
|
||||
var profile = material_node.get_export_profiles()[id]
|
||||
var dialog : FileDialog = FileDialog.new()
|
||||
dialog.rect_min_size = Vector2(500, 500)
|
||||
dialog.access = FileDialog.ACCESS_FILESYSTEM
|
||||
dialog.mode = FileDialog.MODE_SAVE_FILE
|
||||
dialog.add_filter("*."+material_node.get_export_extension(profile)+";"+profile+" Material")
|
||||
add_child(dialog)
|
||||
dialog.connect("file_selected", self, "export_material", [ profile ])
|
||||
dialog.popup_centered()
|
||||
|
||||
|
||||
func create_menu_set_theme(menu) -> void:
|
||||
menu.clear()
|
||||
for t in THEMES:
|
||||
@ -359,15 +398,6 @@ func save_material_as() -> void:
|
||||
func close_material() -> void:
|
||||
projects.close_tab()
|
||||
|
||||
func export_material() -> void:
|
||||
var graph_edit : MMGraphEdit = get_current_graph_edit()
|
||||
if graph_edit != null :
|
||||
graph_edit.export_textures()
|
||||
|
||||
func export_material_is_disabled() -> bool:
|
||||
var graph_edit : MMGraphEdit = get_current_graph_edit()
|
||||
return graph_edit == null or graph_edit.save_path == null
|
||||
|
||||
func quit() -> void:
|
||||
dim_window()
|
||||
get_tree().quit()
|
||||
|
@ -64,7 +64,7 @@ _global_script_classes=[ {
|
||||
"language": "GDScript",
|
||||
"path": "res://addons/material_maker/engine/gen_image.gd"
|
||||
}, {
|
||||
"base": "MMGenBase",
|
||||
"base": "MMGenShader",
|
||||
"class": "MMGenMaterial",
|
||||
"language": "GDScript",
|
||||
"path": "res://addons/material_maker/engine/gen_material.gd"
|
||||
@ -171,7 +171,7 @@ _global_script_class_icons={
|
||||
[application]
|
||||
|
||||
config/name="Material Maker"
|
||||
config/description="An open source, extensible procedural material generation tool"
|
||||
config/description="An open source, extensible procedural material authoring tool"
|
||||
run/main_scene="res://start.tscn"
|
||||
config/use_custom_user_dir=true
|
||||
config/custom_user_dir_name="material_maker"
|
||||
@ -179,7 +179,8 @@ boot_splash/image="res://rodz_labs_logo.png"
|
||||
boot_splash/fullsize=false
|
||||
boot_splash/bg_color=Color( 0.0901961, 0.0941176, 0.141176, 1 )
|
||||
config/icon="res://icon.png"
|
||||
config/release="0.8"
|
||||
config/windows_native_icon="res://icon.ico"
|
||||
config/release="0.9"
|
||||
|
||||
[autoload]
|
||||
|
||||
|
@ -21,7 +21,7 @@ compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=true
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=true
|
||||
flags/anisotropic=false
|
||||
|
98
start.gd
98
start.gd
@ -1,25 +1,88 @@
|
||||
extends Control
|
||||
|
||||
var loader
|
||||
var loader = null
|
||||
|
||||
onready var progress_bar = $VBoxContainer/ProgressBar
|
||||
|
||||
func _ready():
|
||||
set_process(false)
|
||||
var path : String
|
||||
if Directory.new().file_exists("res://material_maker/main_window.tscn"):
|
||||
path = "res://material_maker/main_window.tscn"
|
||||
if OS.get_cmdline_args().size() > 0 && OS.get_cmdline_args()[0] == "--export":
|
||||
var output = []
|
||||
var dir : Directory = Directory.new()
|
||||
match OS.get_name():
|
||||
"Windows":
|
||||
var bat_file_path : String = OS.get_system_dir(OS.SYSTEM_DIR_DOWNLOADS)+"\\mm_cd.bat"
|
||||
var bat_file : File = File.new()
|
||||
bat_file.open(bat_file_path, File.WRITE)
|
||||
bat_file.store_line("cd")
|
||||
bat_file.close()
|
||||
OS.execute(bat_file_path, [], true, output)
|
||||
dir.remove(bat_file_path)
|
||||
dir.change_dir(output[0].split("\n")[2])
|
||||
var target : String = "Godot"
|
||||
var output_dir : String = dir.get_current_dir()
|
||||
var size : int = 0
|
||||
var files : Array = []
|
||||
var i = 1
|
||||
while i < OS.get_cmdline_args().size():
|
||||
match OS.get_cmdline_args()[i]:
|
||||
"-t", "--target":
|
||||
i += 1
|
||||
target = OS.get_cmdline_args()[i]
|
||||
"-o", "--output-dir":
|
||||
i += 1
|
||||
output_dir = OS.get_cmdline_args()[i]
|
||||
"--size":
|
||||
i += 1
|
||||
size = int(OS.get_cmdline_args()[i])
|
||||
if size < 0:
|
||||
show_error("ERROR: incorrect size "+OS.get_cmdline_args()[i])
|
||||
return
|
||||
_:
|
||||
files.push_back(OS.get_cmdline_args()[i])
|
||||
i += 1
|
||||
if !dir.dir_exists(output_dir):
|
||||
show_error("ERROR: Output directory '%s' does not exist" % output_dir)
|
||||
return
|
||||
var expanded_files = []
|
||||
for f in files:
|
||||
var basedir : String = f.get_base_dir()
|
||||
if basedir == "":
|
||||
basedir = "."
|
||||
var basename : String = f.get_file()
|
||||
if basename.find("*") != -1:
|
||||
basename = basename.replace("*", ".*")
|
||||
if dir.open(basedir) == OK:
|
||||
var regex : RegEx = RegEx.new()
|
||||
regex.compile("^"+basename+"$")
|
||||
dir.list_dir_begin()
|
||||
var file_name = dir.get_next()
|
||||
while file_name != "":
|
||||
if regex.search(file_name) && file_name.get_extension() == "ptex":
|
||||
expanded_files.push_back(basedir+"/"+file_name)
|
||||
file_name = dir.get_next()
|
||||
else:
|
||||
expanded_files.push_back(f)
|
||||
export_files(expanded_files, output_dir, target, size)
|
||||
return
|
||||
else:
|
||||
path = "res://material_maker/main_window.tscn"
|
||||
else:
|
||||
path = "res://demo/demo.tscn"
|
||||
loader = ResourceLoader.load_interactive(path)
|
||||
if loader == null: # check for errors
|
||||
print("error")
|
||||
queue_free()
|
||||
set_process(true)
|
||||
|
||||
func _process(_delta):
|
||||
func _process(_delta) -> void:
|
||||
var err = loader.poll()
|
||||
if err == ERR_FILE_EOF:
|
||||
var resource = loader.get_resource()
|
||||
get_node("/root").add_child(resource.instance())
|
||||
var scene = resource.instance()
|
||||
get_node("/root").add_child(scene)
|
||||
queue_free()
|
||||
elif err == OK:
|
||||
var progress = float(loader.get_stage()) / loader.get_stage_count()
|
||||
@ -27,3 +90,30 @@ func _process(_delta):
|
||||
else: # error during loading
|
||||
print("error")
|
||||
queue_free()
|
||||
|
||||
func export_files(files, output_dir, target, size) -> void:
|
||||
$VBoxContainer/ProgressBar.min_value = 0
|
||||
$VBoxContainer/ProgressBar.max_value = files.size()
|
||||
$VBoxContainer/ProgressBar.value = 0
|
||||
for f in files:
|
||||
var gen = mm_loader.load_gen(f)
|
||||
if gen != null:
|
||||
add_child(gen)
|
||||
for c in gen.get_children():
|
||||
if c.has_method("get_export_profiles"):
|
||||
if c.get_export_profiles().find(target) == -1:
|
||||
show_error("ERROR: Unsupported target %s"+target)
|
||||
return
|
||||
$VBoxContainer/Label.text = "Exporting "+f.get_file()
|
||||
var prefix : String = output_dir+"/"+f.get_file().get_basename()
|
||||
var result = c.export_material(prefix, target, size)
|
||||
while result is GDScriptFunctionState:
|
||||
result = yield(result, "completed")
|
||||
break
|
||||
gen.queue_free()
|
||||
$VBoxContainer/ProgressBar.value += 1
|
||||
get_tree().quit()
|
||||
|
||||
func show_error(message : String):
|
||||
$ErrorPanel.show()
|
||||
$ErrorPanel/Label.text = message
|
||||
|
33
start.tscn
33
start.tscn
@ -1,8 +1,16 @@
|
||||
[gd_scene load_steps=3 format=2]
|
||||
[gd_scene load_steps=4 format=2]
|
||||
|
||||
[ext_resource path="res://start.gd" type="Script" id=1]
|
||||
[ext_resource path="res://rodz_labs_logo.png" type="Texture" id=2]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id=1]
|
||||
bg_color = Color( 0.0235294, 0.0313726, 0.12549, 0.929412 )
|
||||
border_width_left = 3
|
||||
border_width_top = 3
|
||||
border_width_right = 3
|
||||
border_width_bottom = 3
|
||||
border_color = Color( 1, 0, 0, 1 )
|
||||
|
||||
[node name="Start" type="Panel"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
@ -40,3 +48,26 @@ align = 1
|
||||
margin_top = 492.0
|
||||
margin_right = 256.0
|
||||
margin_bottom = 506.0
|
||||
|
||||
[node name="ErrorPanel" type="Panel" parent="."]
|
||||
visible = false
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
margin_left = -268.5
|
||||
margin_top = -76.0
|
||||
margin_right = 268.5
|
||||
margin_bottom = 76.0
|
||||
rect_pivot_offset = Vector2( 267.976, 75.7381 )
|
||||
custom_styles/panel = SubResource( 1 )
|
||||
|
||||
[node name="Label" type="Label" parent="ErrorPanel"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = 10.0
|
||||
margin_top = 10.0
|
||||
margin_right = -10.0
|
||||
margin_bottom = -10.0
|
||||
align = 1
|
||||
valign = 1
|
||||
|
Loading…
Reference in New Issue
Block a user