mirror of
https://github.com/Relintai/material-maker.git
synced 2024-12-23 21:16:54 +01:00
Optimized 3D preview and buffer nodes
This commit is contained in:
parent
455dcc7fde
commit
3c87f2c491
@ -117,12 +117,13 @@ func get_parameter(n : String):
|
|||||||
|
|
||||||
func set_parameter(n : String, v) -> void:
|
func set_parameter(n : String, v) -> void:
|
||||||
parameters[n] = v
|
parameters[n] = v
|
||||||
source_changed(0)
|
|
||||||
emit_signal("parameter_changed", n, v)
|
emit_signal("parameter_changed", n, v)
|
||||||
if is_inside_tree():
|
if is_inside_tree():
|
||||||
var parameter_def : Dictionary = get_parameter_def(n)
|
var parameter_def : Dictionary = get_parameter_def(n)
|
||||||
if parameter_def.has("type") and parameter_def.type == "float":
|
if parameter_def.has("type") and parameter_def.type == "float":
|
||||||
get_tree().call_group("preview", "on_float_parameter_changed", "p_o%s_%s" % [ str(get_instance_id()), n ], v)
|
get_tree().call_group("preview", "on_float_parameter_changed", "p_o%s_%s" % [ str(get_instance_id()), n ], v)
|
||||||
|
else:
|
||||||
|
source_changed(0)
|
||||||
|
|
||||||
func notify_output_change(output_index : int) -> void:
|
func notify_output_change(output_index : int) -> void:
|
||||||
var targets = get_targets(output_index)
|
var targets = get_targets(output_index)
|
||||||
|
@ -7,11 +7,16 @@ Texture generator buffers, that render their input in a specific resolution and
|
|||||||
This is useful when using generators that sample their inputs several times (such as convolutions)
|
This is useful when using generators that sample their inputs several times (such as convolutions)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
var updated : bool = false
|
var material : ShaderMaterial = null
|
||||||
|
var updating : bool = false
|
||||||
|
var update_again : bool = false
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
material = ShaderMaterial.new()
|
||||||
|
material.shader = Shader.new()
|
||||||
if !parameters.has("size"):
|
if !parameters.has("size"):
|
||||||
parameters.size = 9
|
parameters.size = 9
|
||||||
|
add_to_group("preview")
|
||||||
|
|
||||||
func get_type() -> String:
|
func get_type() -> String:
|
||||||
return "buffer"
|
return "buffer"
|
||||||
@ -31,20 +36,51 @@ func get_input_defs() -> Array:
|
|||||||
func get_output_defs() -> Array:
|
func get_output_defs() -> Array:
|
||||||
return [ { type="rgba" }, { type="rgba" } ]
|
return [ { type="rgba" }, { type="rgba" } ]
|
||||||
|
|
||||||
func source_changed(input_port_index : int) -> void:
|
func source_changed(_input_port_index : int) -> void:
|
||||||
updated = false
|
if !is_inside_tree():
|
||||||
.source_changed(input_port_index)
|
return
|
||||||
|
var context : MMGenContext = MMGenContext.new()
|
||||||
|
var source = {}
|
||||||
|
var source_output = get_source(0)
|
||||||
|
if source_output != null:
|
||||||
|
source = source_output.generator.get_shader_code("uv", source_output.output_index, context)
|
||||||
|
while source is GDScriptFunctionState:
|
||||||
|
source = yield(source, "completed")
|
||||||
|
if source.empty():
|
||||||
|
source = { defs="", code="", textures={}, rgba="vec4(0.0)" }
|
||||||
|
material.shader.code = mm_renderer.generate_shader(source)
|
||||||
|
if source.has("textures"):
|
||||||
|
for k in source.textures.keys():
|
||||||
|
material.set_shader_param(k, source.textures[k])
|
||||||
|
update_buffer()
|
||||||
|
|
||||||
func _get_shader_code(uv : String, output_index : int, context : MMGenContext) -> Dictionary:
|
func on_float_parameter_changed(n : String, v : float) -> void:
|
||||||
|
material.set_shader_param(n, v)
|
||||||
|
update_buffer()
|
||||||
|
|
||||||
|
func update_buffer():
|
||||||
|
update_again = true
|
||||||
|
if !updating:
|
||||||
|
updating = true
|
||||||
|
while update_again:
|
||||||
|
update_again = false
|
||||||
|
var result = mm_renderer.render_material(material, pow(2, parameters.size))
|
||||||
|
while result is GDScriptFunctionState:
|
||||||
|
result = yield(result, "completed")
|
||||||
|
if !update_again:
|
||||||
|
result.copy_to_texture(texture)
|
||||||
|
result.release()
|
||||||
|
updating = false
|
||||||
|
|
||||||
|
func __get_shader_code(uv : String, output_index : int, context : MMGenContext) -> Dictionary:
|
||||||
var source = get_source(0)
|
var source = get_source(0)
|
||||||
if source != null and !updated:
|
if source != null:
|
||||||
var result = source.generator.render(source.output_index, pow(2, parameters.size))
|
var result = source.generator.render(source.output_index, pow(2, parameters.size))
|
||||||
while result is GDScriptFunctionState:
|
while result is GDScriptFunctionState:
|
||||||
result = yield(result, "completed")
|
result = yield(result, "completed")
|
||||||
result.copy_to_texture(texture)
|
result.copy_to_texture(texture)
|
||||||
result.release()
|
result.release()
|
||||||
texture.flags = Texture.FLAG_MIPMAPS
|
texture.flags = Texture.FLAG_MIPMAPS
|
||||||
updated = true
|
|
||||||
var rv = ._get_shader_code_lod(uv, output_index, context, 0 if output_index == 0 else parameters.lod)
|
var rv = ._get_shader_code_lod(uv, output_index, context, 0 if output_index == 0 else parameters.lod)
|
||||||
while rv is GDScriptFunctionState:
|
while rv is GDScriptFunctionState:
|
||||||
rv = yield(rv, "completed")
|
rv = yield(rv, "completed")
|
||||||
|
@ -5,7 +5,11 @@ class_name MMGenMaterial
|
|||||||
var export_paths = {}
|
var export_paths = {}
|
||||||
|
|
||||||
var material : SpatialMaterial
|
var material : SpatialMaterial
|
||||||
|
var shader_materials = {}
|
||||||
|
var need_update = {}
|
||||||
var generated_textures = {}
|
var generated_textures = {}
|
||||||
|
var updating : bool = false
|
||||||
|
var update_again : bool = false
|
||||||
|
|
||||||
const TEXTURE_LIST = [
|
const TEXTURE_LIST = [
|
||||||
{ port=0, texture="albedo", sources=[0] },
|
{ port=0, texture="albedo", sources=[0] },
|
||||||
@ -38,7 +42,11 @@ const TEXTURE_SIZE_DEFAULT = 10 # 1024x1024
|
|||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
for t in TEXTURE_LIST:
|
for t in TEXTURE_LIST:
|
||||||
generated_textures[t.texture] = null
|
generated_textures[t.texture] = null
|
||||||
|
need_update[t.texture] = true
|
||||||
|
shader_materials[t.texture] = ShaderMaterial.new()
|
||||||
|
shader_materials[t.texture].shader = Shader.new()
|
||||||
material = SpatialMaterial.new()
|
material = SpatialMaterial.new()
|
||||||
|
add_to_group("preview")
|
||||||
|
|
||||||
func can_be_deleted() -> bool:
|
func can_be_deleted() -> bool:
|
||||||
return false
|
return false
|
||||||
@ -74,34 +82,63 @@ func set_parameter(p, v) -> void:
|
|||||||
func source_changed(input_index : int) -> void:
|
func source_changed(input_index : int) -> void:
|
||||||
for t in TEXTURE_LIST:
|
for t in TEXTURE_LIST:
|
||||||
if t.has("sources") and t.sources.find(input_index) != -1:
|
if t.has("sources") and t.sources.find(input_index) != -1:
|
||||||
generated_textures[t.texture] = null
|
need_update[t.texture] = true
|
||||||
update_preview()
|
update_preview()
|
||||||
|
|
||||||
func render_textures() -> void:
|
func render_textures() -> void:
|
||||||
for t in TEXTURE_LIST:
|
for t in TEXTURE_LIST:
|
||||||
var texture = null
|
|
||||||
var result
|
var result
|
||||||
if t.has("port"):
|
if t.has("port"):
|
||||||
if generated_textures[t.texture] != null:
|
if !need_update[t.texture]:
|
||||||
continue
|
continue
|
||||||
result = render(t.port, get_image_size())
|
var context : MMGenContext = MMGenContext.new()
|
||||||
|
var source = get_shader_code("uv", t.port, context)
|
||||||
|
while source is GDScriptFunctionState:
|
||||||
|
source = yield(source, "completed")
|
||||||
|
if source.empty():
|
||||||
|
source = { defs="", code="", textures={}, rgba="vec4(0.0)" }
|
||||||
|
shader_materials[t.texture].shader.code = mm_renderer.generate_shader(source)
|
||||||
|
if source.has("textures"):
|
||||||
|
for k in source.textures.keys():
|
||||||
|
shader_materials[t.texture].set_shader_param(k, source.textures[k])
|
||||||
|
result = mm_renderer.render_material(shader_materials[t.texture], get_image_size())
|
||||||
else:
|
else:
|
||||||
generated_textures[t.texture] = null
|
generated_textures[t.texture] = null
|
||||||
|
need_update[t.texture] = false
|
||||||
continue
|
continue
|
||||||
while result is GDScriptFunctionState:
|
while result is GDScriptFunctionState:
|
||||||
result = yield(result, "completed")
|
result = yield(result, "completed")
|
||||||
texture = ImageTexture.new()
|
if generated_textures[t.texture] == null:
|
||||||
|
generated_textures[t.texture] = ImageTexture.new()
|
||||||
|
var texture = generated_textures[t.texture]
|
||||||
result.copy_to_texture(texture)
|
result.copy_to_texture(texture)
|
||||||
result.release()
|
result.release()
|
||||||
# To work, this must be set after calling `copy_to_texture()`
|
# To work, this must be set after calling `copy_to_texture()`
|
||||||
texture.flags |= ImageTexture.FLAG_ANISOTROPIC_FILTER
|
texture.flags |= ImageTexture.FLAG_ANISOTROPIC_FILTER
|
||||||
|
|
||||||
# Disable filtering for small textures, as they're considered to be used
|
# Disable filtering for small textures, as they're considered to be used
|
||||||
# for a pixel art style
|
# for a pixel art style
|
||||||
if texture.get_size().x <= 128:
|
if texture.get_size().x <= 128:
|
||||||
texture.flags ^= ImageTexture.FLAG_FILTER
|
texture.flags ^= ImageTexture.FLAG_FILTER
|
||||||
|
need_update[t.texture] = false
|
||||||
|
|
||||||
generated_textures[t.texture] = texture
|
func on_float_parameter_changed(n : String, v : float) -> void:
|
||||||
|
var image_size = get_image_size()
|
||||||
|
for t in TEXTURE_LIST:
|
||||||
|
if generated_textures[t.texture] != null:
|
||||||
|
shader_materials[t.texture].set_shader_param(n, v)
|
||||||
|
update_again = true
|
||||||
|
if !updating:
|
||||||
|
updating = true
|
||||||
|
while update_again:
|
||||||
|
update_again = false
|
||||||
|
for t in TEXTURE_LIST:
|
||||||
|
if generated_textures[t.texture] != null:
|
||||||
|
var result = mm_renderer.render_material(shader_materials[t.texture], image_size)
|
||||||
|
while result is GDScriptFunctionState:
|
||||||
|
result = yield(result, "completed")
|
||||||
|
result.copy_to_texture(generated_textures[t.texture])
|
||||||
|
result.release()
|
||||||
|
updating = false
|
||||||
|
|
||||||
func update_materials(material_list) -> void:
|
func update_materials(material_list) -> void:
|
||||||
render_textures()
|
render_textures()
|
||||||
|
@ -5,19 +5,24 @@ class_name MMGenRenderer
|
|||||||
export(String) var debug_path = ""
|
export(String) var debug_path = ""
|
||||||
var debug_file_index : int = 0
|
var debug_file_index : int = 0
|
||||||
|
|
||||||
|
var common_shader : String
|
||||||
|
|
||||||
var rendering : bool = false
|
var rendering : bool = false
|
||||||
|
|
||||||
signal done
|
signal done
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
$ColorRect.material = $ColorRect.material.duplicate(true)
|
$ColorRect.material = $ColorRect.material.duplicate(true)
|
||||||
|
var file = File.new()
|
||||||
|
file.open("res://addons/material_maker/common.shader", File.READ)
|
||||||
|
common_shader = file.get_as_text()
|
||||||
|
|
||||||
static func generate_shader(src_code) -> String:
|
func generate_shader(src_code) -> String:
|
||||||
var code
|
var code
|
||||||
code = "shader_type canvas_item;\n"
|
code = "shader_type canvas_item;\n"
|
||||||
code += "render_mode blend_disabled;\n"
|
code += "render_mode blend_disabled;\n"
|
||||||
var file = File.new()
|
code += common_shader
|
||||||
file.open("res://addons/material_maker/common.shader", File.READ)
|
|
||||||
code += file.get_as_text()
|
|
||||||
code += "\n"
|
code += "\n"
|
||||||
if src_code.has("textures"):
|
if src_code.has("textures"):
|
||||||
for t in src_code.textures.keys():
|
for t in src_code.textures.keys():
|
||||||
@ -38,13 +43,11 @@ static func generate_shader(src_code) -> String:
|
|||||||
code += shader_code
|
code += shader_code
|
||||||
return code
|
return code
|
||||||
|
|
||||||
static func generate_combined_shader(red_code, green_code, blue_code) -> String:
|
func generate_combined_shader(red_code, green_code, blue_code) -> String:
|
||||||
var code
|
var code
|
||||||
code = "shader_type canvas_item;\n"
|
code = "shader_type canvas_item;\n"
|
||||||
code += "render_mode blend_disabled;\n"
|
code += "render_mode blend_disabled;\n"
|
||||||
var file = File.new()
|
code += common_shader
|
||||||
file.open("res://addons/material_maker/common.shader", File.READ)
|
|
||||||
code += file.get_as_text()
|
|
||||||
code += "\n"
|
code += "\n"
|
||||||
var globals = []
|
var globals = []
|
||||||
var textures = {}
|
var textures = {}
|
||||||
@ -84,6 +87,22 @@ func setup_material(shader_material, textures, shader_code) -> void:
|
|||||||
shader_material.set_shader_param(k+"_tex", textures[k])
|
shader_material.set_shader_param(k+"_tex", textures[k])
|
||||||
shader_material.shader.code = shader_code
|
shader_material.shader.code = shader_code
|
||||||
|
|
||||||
|
func render_material(material, render_size) -> Object:
|
||||||
|
while rendering:
|
||||||
|
yield(self, "done")
|
||||||
|
rendering = true
|
||||||
|
var shader_material = $ColorRect.material
|
||||||
|
size = Vector2(render_size, render_size)
|
||||||
|
$ColorRect.rect_position = Vector2(0, 0)
|
||||||
|
$ColorRect.rect_size = size
|
||||||
|
$ColorRect.material = material
|
||||||
|
render_target_update_mode = Viewport.UPDATE_ONCE
|
||||||
|
update_worlds()
|
||||||
|
yield(get_tree(), "idle_frame")
|
||||||
|
yield(get_tree(), "idle_frame")
|
||||||
|
$ColorRect.material = shader_material
|
||||||
|
return self
|
||||||
|
|
||||||
func render_shader(shader, textures, render_size) -> Object:
|
func render_shader(shader, textures, render_size) -> Object:
|
||||||
if debug_path != null and debug_path != "":
|
if debug_path != null and debug_path != "":
|
||||||
var file_name = debug_path+str(debug_file_index)+".shader"
|
var file_name = debug_path+str(debug_file_index)+".shader"
|
||||||
|
@ -95,7 +95,8 @@ func _on_value_changed(new_value, variable) -> void:
|
|||||||
ignore_parameter_change = variable
|
ignore_parameter_change = variable
|
||||||
generator.set_parameter(variable, new_value)
|
generator.set_parameter(variable, new_value)
|
||||||
ignore_parameter_change = ""
|
ignore_parameter_change = ""
|
||||||
update_shaders()
|
if ! (new_value is float):
|
||||||
|
update_shaders()
|
||||||
|
|
||||||
func _on_color_changed(new_color, variable) -> void:
|
func _on_color_changed(new_color, variable) -> void:
|
||||||
ignore_parameter_change = variable
|
ignore_parameter_change = variable
|
||||||
|
@ -5,15 +5,12 @@ export(String, MULTILINE) var shader : String = ""
|
|||||||
var generator : MMGenBase = null
|
var generator : MMGenBase = null
|
||||||
|
|
||||||
func set_generator(g : MMGenBase) -> void:
|
func set_generator(g : MMGenBase) -> void:
|
||||||
if generator != null and is_instance_valid(generator):
|
|
||||||
generator.disconnect("float_param_changed", self, "on_float_param_changed")
|
|
||||||
var source = { defs="", code="", textures={}, type="f", f="1.0" }
|
var source = { defs="", code="", textures={}, type="f", f="1.0" }
|
||||||
if is_instance_valid(g):
|
if is_instance_valid(g):
|
||||||
generator = g
|
generator = g
|
||||||
var param_defs : Array = generator.get_parameter_defs()
|
var param_defs : Array = generator.get_parameter_defs()
|
||||||
for c in get_children():
|
for c in get_children():
|
||||||
c.setup_control(generator, param_defs)
|
c.setup_control(generator, param_defs)
|
||||||
generator.connect("float_param_changed", self, "on_float_param_changed")
|
|
||||||
var gen_output_defs = generator.get_output_defs()
|
var gen_output_defs = generator.get_output_defs()
|
||||||
if ! gen_output_defs.empty():
|
if ! gen_output_defs.empty():
|
||||||
var context : MMGenContext = MMGenContext.new()
|
var context : MMGenContext = MMGenContext.new()
|
||||||
@ -27,6 +24,9 @@ func set_generator(g : MMGenBase) -> void:
|
|||||||
for c in get_children():
|
for c in get_children():
|
||||||
c.setup_control(generator, [])
|
c.setup_control(generator, [])
|
||||||
material.shader.code = MMGenBase.generate_preview_shader(source, source.type, shader)
|
material.shader.code = MMGenBase.generate_preview_shader(source, source.type, shader)
|
||||||
|
if source.has("textures"):
|
||||||
|
for k in source.textures.keys():
|
||||||
|
material.set_shader_param(k, source.textures[k])
|
||||||
|
|
||||||
func on_float_parameter_changed(n : String, v : float) -> void:
|
func on_float_parameter_changed(n : String, v : float) -> void:
|
||||||
material.set_shader_param(n, v)
|
material.set_shader_param(n, v)
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
extends ViewportContainer
|
extends ViewportContainer
|
||||||
|
|
||||||
const ENVIRONMENTS = [
|
|
||||||
"experiment", "lobby", "night", "park", "schelde"
|
|
||||||
]
|
|
||||||
|
|
||||||
const CAMERA_DISTANCE_MIN = 1.0
|
const CAMERA_DISTANCE_MIN = 1.0
|
||||||
const CAMERA_DISTANCE_MAX = 10.0
|
const CAMERA_DISTANCE_MAX = 10.0
|
||||||
|
|
||||||
|
@ -3,10 +3,11 @@
|
|||||||
[ext_resource path="res://material_maker/preview/preview_3d.gd" type="Script" id=1]
|
[ext_resource path="res://material_maker/preview/preview_3d.gd" type="Script" id=1]
|
||||||
[ext_resource path="res://material_maker/preview/preview_3d_scene.tscn" type="PackedScene" id=2]
|
[ext_resource path="res://material_maker/preview/preview_3d_scene.tscn" type="PackedScene" id=2]
|
||||||
|
|
||||||
|
|
||||||
[sub_resource type="World" id=1]
|
[sub_resource type="World" id=1]
|
||||||
|
|
||||||
[node name="Preview3D" type="ViewportContainer"]
|
[node name="Preview3D" type="ViewportContainer" groups=[
|
||||||
|
"preview",
|
||||||
|
]]
|
||||||
visible = false
|
visible = false
|
||||||
anchor_right = 1.0
|
anchor_right = 1.0
|
||||||
anchor_bottom = 1.0
|
anchor_bottom = 1.0
|
||||||
|
Loading…
Reference in New Issue
Block a user