From 19931fac88187910d2b34514751cb1116c6f36f5 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Sat, 8 Feb 2020 19:55:38 +0100 Subject: [PATCH 01/62] introduced prelit changes --- io_mesh_w3d/common/utils/material_import.py | 1 + io_mesh_w3d/common/utils/mesh_export.py | 138 +++++++++++++++++--- io_mesh_w3d/common/utils/mesh_import.py | 36 ++++- tests/common/cases/test_utils.py | 14 +- tests/common/helpers/mesh.py | 2 +- tests/w3d/helpers/mesh_structs/prelit.py | 2 +- 6 files changed, 166 insertions(+), 27 deletions(-) diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index d2968058..9ea54234 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -18,6 +18,7 @@ def create_vertex_material(context, principleds, structure, mesh, name, triangle (material, principled) = create_material_from_vertex_material(name, vertMat) mesh.materials.append(material) principleds.append(principled) + materials.append(material) b_mesh = bmesh.new() b_mesh.from_mesh(mesh) diff --git a/io_mesh_w3d/common/utils/mesh_export.py b/io_mesh_w3d/common/utils/mesh_export.py index 7777df84..2d036e10 100644 --- a/io_mesh_w3d/common/utils/mesh_export.py +++ b/io_mesh_w3d/common/utils/mesh_export.py @@ -160,19 +160,16 @@ def retrieve_meshes(context, hierarchy, rig, container_name, force_vertex_materi mat_pass.tx_coords = tx_stages[i].tx_coords mesh_struct.shader_materials.append( retrieve_shader_material(context, material, principled)) - + mesh_struct.material_passes.append(mat_pass) else: - # TODO: create prelit material structs if material is prelit - # set mesh_struct.header.attributes accordingly + shader = retrieve_shader(material) - mesh_struct.shaders.append(retrieve_shader(material)) - mat_pass.shader_ids = [i] - mat_pass.vertex_material_ids = [i] if i < len(tx_stages): mat_pass.tx_stages.append(tx_stages[i]) - mesh_struct.vert_materials.append( - retrieve_vertex_material(material)) + vert_material = retrieve_vertex_material(material) + + tex = None if principled.base_color_texture.image is not None: info = TextureInfo() img = principled.base_color_texture.image @@ -183,9 +180,81 @@ def retrieve_meshes(context, hierarchy, rig, container_name, force_vertex_materi id=img.name, file=filepath, texture_info=info) - mesh_struct.textures.append(tex) - mesh_struct.material_passes.append(mat_pass) + if material.material_type == 'VERTEX_MATERIAL': + mat_pass.shader_ids = [i] + mat_pass.vertex_material_ids = [i] + mesh_struct.shaders.append(shader) + mesh_struct.vert_materials.append(vert_material) + mesh_struct.material_passes.append(mat_pass) + if tex is not None: + mesh_struct.textures.append(tex) + else: + if material.prelit_type == 'PRELIT_UNLIT': + if mesh_struct.prelit_unlit is None: + mesh_struct.prelit_unlit = PrelitBase( + type=W3D_CHUNK_PRELIT_UNLIT, + shaders=[], + vert_materials=[], + material_passes=[], + textures=[]) + + mat_pass.shader_ids = [len(mesh_struct.prelit_unlit.shaders)] + mat_pass.vertex_material_ids = [len(mesh_struct.prelit_unlit.vert_materials)] + mesh_struct.prelit_unlit.shaders.append(shader) + mesh_struct.prelit_unlit.vert_materials.append(vert_material) + mesh_struct.prelit_unlit.material_passes.append(mat_pass) + if tex is not None: + mesh_struct.prelit_unlit.textures.append(tex) + + elif material.prelit_type == 'PRELIT_VERTEX': + if mesh_struct.prelit_vertex is None: + mesh_struct.prelit_vertex = PrelitBase(type=W3D_CHUNK_PRELIT_VERTEX, + shaders=[], + vert_materials=[], + material_passes=[], + textures=[]) + + mat_pass.shader_ids = [len(mesh_struct.prelit_vertex.shaders)] + mat_pass.vertex_material_ids = [len(mesh_struct.prelit_vertex.vert_materials)] + mesh_struct.prelit_vertex.shaders.append(shader) + mesh_struct.prelit_vertex.vert_materials.append(vert_material) + mesh_struct.prelit_vertex.material_passes.append(mat_pass) + if tex is not None: + mesh_struct.prelit_vertex.textures.append(tex) + + elif material.prelit_type == 'PRELIT_LIGHTMAP_MULTI_PASS': + if mesh_struct.prelit_lightmap_multi_pass is None: + mesh_struct.prelit_lightmap_multi_pass = PrelitBase(type=W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_PASS, + shaders=[], + vert_materials=[], + material_passes=[], + textures=[]) + + mat_pass.shader_ids = [len(mesh_struct.prelit_lightmap_multi_pass.shaders)] + mat_pass.vertex_material_ids = [len(mesh_struct.prelit_lightmap_multi_pass.vert_materials)] + mesh_struct.prelit_lightmap_multi_pass.shaders.append(shader) + mesh_struct.prelit_lightmap_multi_pass.vert_materials.append(vert_material) + mesh_struct.prelit_lightmap_multi_pass.material_passes.append(mat_pass) + if tex is not None: + mesh_struct.prelit_lightmap_multi_pass.textures.append(tex) + + elif material.prelit_type == 'PRELIT_LIGHTMAP_MULTI_TEXTURE': + if mesh_struct.prelit_lightmap_multi_texture is None: + mesh_struct.prelit_lightmap_multi_texture = PrelitBase(type=W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_TEXTURE, + shaders=[], + vert_materials=[], + material_passes=[], + textures=[]) + + mat_pass.shader_ids = [len(mesh_struct.prelit_lightmap_multi_texture.shaders)] + mat_pass.vertex_material_ids = [len(mesh_struct.prelit_lightmap_multi_texture.vert_materials)] + mesh_struct.prelit_lightmap_multi_texture.shaders.append(shader) + mesh_struct.prelit_lightmap_multi_texture.vert_materials.append(vert_material) + mesh_struct.prelit_lightmap_multi_texture.material_passes.append(mat_pass) + if tex is not None: + mesh_struct.prelit_lightmap_multi_texture.textures.append(tex) + header.vert_channel_flags = VERTEX_CHANNEL_LOCATION | VERTEX_CHANNEL_NORMAL @@ -195,11 +264,50 @@ def retrieve_meshes(context, hierarchy, rig, container_name, force_vertex_materi mesh_struct.tangents = [] mesh_struct.bitangents = [] - mesh_struct.mat_info = MaterialInfo( - pass_count=len(mesh_struct.material_passes), - vert_matl_count=len(mesh_struct.vert_materials), - shader_count=len(mesh_struct.shaders), - texture_count=len(mesh_struct.textures)) + if mesh_struct.prelit_unlit is not None: + mesh_struct.header.attrs |= PRELIT_UNLIT + prelit = mesh_struct.prelit_unlit + prelit.mat_info = MaterialInfo( + pass_count=len(prelit.material_passes), + vert_matl_count=len(prelit.vert_materials), + shader_count=len(prelit.shaders), + texture_count=len(prelit.textures)) + + if mesh_struct.prelit_vertex is not None: + mesh_struct.header.attrs |= PRELIT_VERTEX + prelit = mesh_struct.prelit_vertex + prelit.mat_info = MaterialInfo( + pass_count=len(prelit.material_passes), + vert_matl_count=len(prelit.vert_materials), + shader_count=len(prelit.shaders), + texture_count=len(prelit.textures)) + + if mesh_struct.prelit_lightmap_multi_pass is not None: + mesh_struct.header.attrs |= PRELIT_LIGHTMAP_MULTI_PASS + prelit = mesh_struct.prelit_lightmap_multi_pass + prelit.mat_info = MaterialInfo( + pass_count=len(prelit.material_passes), + vert_matl_count=len(prelit.vert_materials), + shader_count=len(prelit.shaders), + texture_count=len(prelit.textures)) + + if mesh_struct.prelit_lightmap_multi_texture is not None: + mesh_struct.header.attrs |= PRELIT_LIGHTMAP_MULTI_TEXTURE + prelit = mesh_struct.prelit_lightmap_multi_texture + prelit.mat_info = MaterialInfo( + pass_count=len(prelit.material_passes), + vert_matl_count=len(prelit.vert_materials), + shader_count=len(prelit.shaders), + texture_count=len(prelit.textures)) + + + if mesh_struct.prelit_unlit is None and mesh_struct.prelit_vertex is None \ + and mesh_struct.prelit_lightmap_multi_pass is None and mesh_struct.prelit_lightmap_multi_texture is None: + mesh_struct.mat_info = MaterialInfo( + pass_count=len(mesh_struct.material_passes), + vert_matl_count=len(mesh_struct.vert_materials), + shader_count=len(mesh_struct.shaders), + texture_count=len(mesh_struct.textures)) mesh_struct.header.matl_count = max( len(mesh_struct.vert_materials), len(mesh_struct.shader_materials)) diff --git a/io_mesh_w3d/common/utils/mesh_import.py b/io_mesh_w3d/common/utils/mesh_import.py index a0f88a46..4045a767 100644 --- a/io_mesh_w3d/common/utils/mesh_import.py +++ b/io_mesh_w3d/common/utils/mesh_import.py @@ -35,10 +35,38 @@ def create_mesh(context, mesh_struct, coll): # vertex material stuff name = mesh_struct.name() if mesh_struct.vert_materials: - create_vertex_material(context, principleds, mesh_struct, mesh, name, triangles) - - for i, shader in enumerate(mesh_struct.shaders): - set_shader_properties(mesh.materials[i], shader) + materials = [] + create_vertex_material(context, principleds, materials, mesh_struct, mesh, name, triangles) + for i, shader in enumerate(mesh_struct.shaders): + set_shader_properties(materials[i], shader) + + if mesh_struct.prelit_unlit is not None: + materials = [] + prelit = mesh_struct.prelit_unlit + create_vertex_material(context, principleds, materials, prelit, mesh, name, triangles, prelit_type='PRELIT_UNLIT') + for i, shader in enumerate(prelit.shaders): + set_shader_properties(materials[i], shader) + + if mesh_struct.prelit_vertex is not None: + materials = [] + prelit = mesh_struct.prelit_vertex + create_vertex_material(context, principleds, materials, prelit, mesh, name, triangles, prelit_type='PRELIT_VERTEX') + for i, shader in enumerate(prelit.shaders): + set_shader_properties(materials[i], shader) + + if mesh_struct.prelit_lightmap_multi_pass is not None: + materials = [] + prelit = mesh_struct.prelit_lightmap_multi_pass + create_vertex_material(context, principleds, materials, prelit, mesh, name, triangles, prelit_type='PRELIT_LIGHTMAP_MULTI_PASS') + for i, shader in enumerate(prelit.shaders): + set_shader_properties(materials[i], shader) + + if mesh_struct.prelit_lightmap_multi_texture is not None: + materials = [] + prelit = mesh_struct.prelit_lightmap_multi_texture + create_vertex_material(context, principleds, materials, prelit, mesh, name, triangles, prelit_type='PRELIT_LIGHTMAP_MULTI_TEXTURE') + for i, shader in enumerate(prelit.shaders): + set_shader_properties(materials[i], shader) # shader material stuff if mesh_struct.shader_materials: diff --git a/tests/common/cases/test_utils.py b/tests/common/cases/test_utils.py index b33401a1..6e270cf8 100644 --- a/tests/common/cases/test_utils.py +++ b/tests/common/cases/test_utils.py @@ -576,14 +576,16 @@ def test_hidden_meshes_roundtrip(self): self.compare_data(meshes) def test_prelit_meshes_roundtrip(self): - hlod = get_hlod() - hierarchy = get_hierarchy() - meshes = [get_mesh(name='sword', skin=True, prelit=True)] + meshes = [get_mesh(name='prelit', prelit=True)] - create_data(self, meshes, hlod, hierarchy) + copyfile(up(up(self.relpath())) + '/testfiles/texture.dds', + self.outpath() + 'texture.dds') - # not yet supported - # self.compare_data(meshes, None, None) + + print('################# Prelit test') + create_data(self, meshes) + + self.compare_data(meshes) def test_animation_roundtrip(self): animation = get_animation() diff --git a/tests/common/helpers/mesh.py b/tests/common/helpers/mesh.py index f692e621..b530720b 100644 --- a/tests/common/helpers/mesh.py +++ b/tests/common/helpers/mesh.py @@ -140,7 +140,7 @@ def get_mesh(name='meshName', skin=False, shader_mats=False, prelit=False, hidde mesh.shader_materials.append(get_shader_material()) mesh.material_passes.append(get_material_pass(index=0, shader_mat=shader_mats)) elif prelit: - mesh.header.attrs |= PRELIT_VERTEX + mesh.header.attrs |= PRELIT_UNLIT | PRELIT_VERTEX | PRELIT_LIGHTMAP_MULTI_PASS | PRELIT_LIGHTMAP_MULTI_TEXTURE mesh.prelit_unlit = get_prelit(type=W3D_CHUNK_PRELIT_UNLIT, count=1) mesh.prelit_vertex = get_prelit(type=W3D_CHUNK_PRELIT_VERTEX, count=1) mesh.prelit_lightmap_multi_pass = get_prelit( diff --git a/tests/w3d/helpers/mesh_structs/prelit.py b/tests/w3d/helpers/mesh_structs/prelit.py index 23ac75e9..89071528 100644 --- a/tests/w3d/helpers/mesh_structs/prelit.py +++ b/tests/w3d/helpers/mesh_structs/prelit.py @@ -35,7 +35,7 @@ def get_prelit(type=W3D_CHUNK_PRELIT_UNLIT, count=1): vm_name = 'W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_TEXTURE' for i in range(count): - result.material_passes.append(get_material_pass()) + result.material_passes.append(get_material_pass(index=i)) name = vm_name + str(i) result.vert_materials.append(get_vertex_material(vm_name=name)) result.textures.append(get_texture()) From fab239b23949029560dd24c1877591fbf36656a6 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Sat, 8 Feb 2020 20:56:20 +0100 Subject: [PATCH 02/62] added some prints --- io_mesh_w3d/common/utils/material_import.py | 5 +++++ io_mesh_w3d/common/utils/mesh_export.py | 7 +++++++ io_mesh_w3d/common/utils/mesh_import.py | 4 ++++ tests/common/cases/test_utils.py | 2 +- 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index 9ea54234..ba537fd8 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -18,6 +18,11 @@ def create_vertex_material(context, principleds, structure, mesh, name, triangle (material, principled) = create_material_from_vertex_material(name, vertMat) mesh.materials.append(material) principleds.append(principled) + + if prelit_type is not None: + material.material_type = 'PRELIT_MATERIAL' + material.prelit_type = prelit_type + materials.append(material) b_mesh = bmesh.new() diff --git a/io_mesh_w3d/common/utils/mesh_export.py b/io_mesh_w3d/common/utils/mesh_export.py index 2d036e10..1d141af0 100644 --- a/io_mesh_w3d/common/utils/mesh_export.py +++ b/io_mesh_w3d/common/utils/mesh_export.py @@ -181,6 +181,7 @@ def retrieve_meshes(context, hierarchy, rig, container_name, force_vertex_materi file=filepath, texture_info=info) + #print('material type: ' + material.material_type) if material.material_type == 'VERTEX_MATERIAL': mat_pass.shader_ids = [i] mat_pass.vertex_material_ids = [i] @@ -190,6 +191,7 @@ def retrieve_meshes(context, hierarchy, rig, container_name, force_vertex_materi if tex is not None: mesh_struct.textures.append(tex) else: + #print('prelit type: ' + material.prelit_type) if material.prelit_type == 'PRELIT_UNLIT': if mesh_struct.prelit_unlit is None: mesh_struct.prelit_unlit = PrelitBase( @@ -265,6 +267,7 @@ def retrieve_meshes(context, hierarchy, rig, container_name, force_vertex_materi mesh_struct.bitangents = [] if mesh_struct.prelit_unlit is not None: + # print('prelit unlit') mesh_struct.header.attrs |= PRELIT_UNLIT prelit = mesh_struct.prelit_unlit prelit.mat_info = MaterialInfo( @@ -274,6 +277,7 @@ def retrieve_meshes(context, hierarchy, rig, container_name, force_vertex_materi texture_count=len(prelit.textures)) if mesh_struct.prelit_vertex is not None: + # print('prelit vertex') mesh_struct.header.attrs |= PRELIT_VERTEX prelit = mesh_struct.prelit_vertex prelit.mat_info = MaterialInfo( @@ -283,6 +287,7 @@ def retrieve_meshes(context, hierarchy, rig, container_name, force_vertex_materi texture_count=len(prelit.textures)) if mesh_struct.prelit_lightmap_multi_pass is not None: + # print('prelit lightmap multi pass') mesh_struct.header.attrs |= PRELIT_LIGHTMAP_MULTI_PASS prelit = mesh_struct.prelit_lightmap_multi_pass prelit.mat_info = MaterialInfo( @@ -292,6 +297,7 @@ def retrieve_meshes(context, hierarchy, rig, container_name, force_vertex_materi texture_count=len(prelit.textures)) if mesh_struct.prelit_lightmap_multi_texture is not None: + # print('prelit lightmap multi texture') mesh_struct.header.attrs |= PRELIT_LIGHTMAP_MULTI_TEXTURE prelit = mesh_struct.prelit_lightmap_multi_texture prelit.mat_info = MaterialInfo( @@ -303,6 +309,7 @@ def retrieve_meshes(context, hierarchy, rig, container_name, force_vertex_materi if mesh_struct.prelit_unlit is None and mesh_struct.prelit_vertex is None \ and mesh_struct.prelit_lightmap_multi_pass is None and mesh_struct.prelit_lightmap_multi_texture is None: + # print('NO PRELIT') mesh_struct.mat_info = MaterialInfo( pass_count=len(mesh_struct.material_passes), vert_matl_count=len(mesh_struct.vert_materials), diff --git a/io_mesh_w3d/common/utils/mesh_import.py b/io_mesh_w3d/common/utils/mesh_import.py index 4045a767..b2942b16 100644 --- a/io_mesh_w3d/common/utils/mesh_import.py +++ b/io_mesh_w3d/common/utils/mesh_import.py @@ -41,6 +41,7 @@ def create_mesh(context, mesh_struct, coll): set_shader_properties(materials[i], shader) if mesh_struct.prelit_unlit is not None: + print('create prelit unlit') materials = [] prelit = mesh_struct.prelit_unlit create_vertex_material(context, principleds, materials, prelit, mesh, name, triangles, prelit_type='PRELIT_UNLIT') @@ -48,6 +49,7 @@ def create_mesh(context, mesh_struct, coll): set_shader_properties(materials[i], shader) if mesh_struct.prelit_vertex is not None: + print('create prelit vertex') materials = [] prelit = mesh_struct.prelit_vertex create_vertex_material(context, principleds, materials, prelit, mesh, name, triangles, prelit_type='PRELIT_VERTEX') @@ -55,6 +57,7 @@ def create_mesh(context, mesh_struct, coll): set_shader_properties(materials[i], shader) if mesh_struct.prelit_lightmap_multi_pass is not None: + print('create prelit lightmap multi pass') materials = [] prelit = mesh_struct.prelit_lightmap_multi_pass create_vertex_material(context, principleds, materials, prelit, mesh, name, triangles, prelit_type='PRELIT_LIGHTMAP_MULTI_PASS') @@ -62,6 +65,7 @@ def create_mesh(context, mesh_struct, coll): set_shader_properties(materials[i], shader) if mesh_struct.prelit_lightmap_multi_texture is not None: + print('create prelit lightmap multi texture') materials = [] prelit = mesh_struct.prelit_lightmap_multi_texture create_vertex_material(context, principleds, materials, prelit, mesh, name, triangles, prelit_type='PRELIT_LIGHTMAP_MULTI_TEXTURE') diff --git a/tests/common/cases/test_utils.py b/tests/common/cases/test_utils.py index 6e270cf8..650b35c0 100644 --- a/tests/common/cases/test_utils.py +++ b/tests/common/cases/test_utils.py @@ -19,7 +19,6 @@ from tests.w3d.helpers.dazzle import * from tests.w3d.helpers.mesh_structs.shader import * from tests.w3d.helpers.mesh_structs.vertex_material import * -from os.path import dirname as up class TestUtils(TestCase): @@ -585,6 +584,7 @@ def test_prelit_meshes_roundtrip(self): print('################# Prelit test') create_data(self, meshes) + print('##### created data') self.compare_data(meshes) def test_animation_roundtrip(self): From d5e8166bec24c896827074483e6ac5e8ede74048 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Mon, 10 Feb 2020 17:07:46 +0100 Subject: [PATCH 03/62] refactor material tests --- tests/common/cases/test_utils.py | 105 +++++++++++++++---------------- 1 file changed, 52 insertions(+), 53 deletions(-) diff --git a/tests/common/cases/test_utils.py b/tests/common/cases/test_utils.py index 650b35c0..2a9a0d05 100644 --- a/tests/common/cases/test_utils.py +++ b/tests/common/cases/test_utils.py @@ -23,95 +23,94 @@ class TestUtils(TestCase): def test_vertex_material_roundtrip(self): - mesh = get_mesh() + expected = get_vertex_material() copyfile(up(up(self.relpath())) + '/testfiles/texture.dds', self.outpath() + 'texture.dds') - for source in mesh.vert_materials: - (material, _) = create_material_from_vertex_material(mesh.name(), source) - actual = retrieve_vertex_material(material) - compare_vertex_materials(self, source, actual) + (material, _) = create_material_from_vertex_material( + self, 'meshName', expected) + actual = retrieve_vertex_material(material) + compare_vertex_materials(self, expected, actual) def test_vertex_material_no_attributes_roundtrip(self): - mesh = get_mesh() + expected = get_vertex_material() + + copyfile(up(up(self.relpath())) + '/testfiles/texture.dds', + self.outpath() + 'texture.dds') - for source in mesh.vert_materials: - source.vm_info.attributes = 0 - (material, _) = create_material_from_vertex_material(mesh.name(), source) - actual = retrieve_vertex_material(material) - compare_vertex_materials(self, source, actual) + expected.vm_info.attributes = 0 + (material, _) = create_material_from_vertex_material( + self, 'meshName', expected) + actual = retrieve_vertex_material(material) + compare_vertex_materials(self, expected, actual) def test_shader_material_roundtrip(self): - mesh = get_mesh(shader_mats=True) - mesh.shader_materials = [get_shader_material()] + expected = get_shader_material() copyfile(up(up(self.relpath())) + '/testfiles/texture.dds', self.outpath() + 'texture.dds') - for source in mesh.shader_materials: - (material, _) = create_material_from_shader_material(self, mesh.name(), source) - principled = node_shader_utils.PrincipledBSDFWrapper(material, is_readonly=True) - actual = retrieve_shader_material(self, material, principled) - compare_shader_materials(self, source, actual) + (material, _) = create_material_from_shader_material( + self, 'meshName', expected) + principled = node_shader_utils.PrincipledBSDFWrapper(material, is_readonly=True) + actual = retrieve_shader_material(material, principled) + compare_shader_materials(self, expected, actual) def test_duplicate_shader_material_roundtrip(self): - mesh = get_mesh(shader_mats=True) - mesh.shader_materials = [get_shader_material(), get_shader_material()] + expecteds = [get_shader_material(), get_shader_material()] materials = [] - for mat in mesh.shader_materials: + for mat in expecteds: (material, _) = create_material_from_shader_material(self, 'meshName', mat) materials.append(material) self.assertEqual(1, len(bpy.data.materials)) self.assertTrue('meshName.NormalMapped.fx' in bpy.data.materials) - for i, expected in enumerate(mesh.shader_materials): - principled = node_shader_utils.PrincipledBSDFWrapper(materials[i], is_readonly=True) - actual = retrieve_shader_material(self, materials[i], principled) + for expected in expecteds: + principled = node_shader_utils.PrincipledBSDFWrapper(material, is_readonly=True) + actual = retrieve_shader_material(self, material, principled) compare_shader_materials(self, expected, actual) def test_shader_material_w3x_roundtrip(self): - mesh = get_mesh(shader_mats=True) - mesh.shader_materials = [get_shader_material(w3x=True)] - copyfile(up(up(self.relpath())) + '/testfiles/texture.dds', self.outpath() + 'texture.dds') + expected = get_shader_material(w3x=True) + copyfile(up(up(self.relpath())) + '/testfiles/texture.dds', + self.outpath() + 'texture.dds') - for source in mesh.shader_materials: - (material, _) = create_material_from_shader_material(self, mesh.name(), source) - principled = node_shader_utils.PrincipledBSDFWrapper(material, is_readonly=True) - actual = retrieve_shader_material(self, material, principled, w3x=True) - compare_shader_materials(self, source, actual) + (material, _) = create_material_from_shader_material( + self, 'meshName', expected) + principled = node_shader_utils.PrincipledBSDFWrapper(material, is_readonly=True) + actual = retrieve_shader_material(material, principled, w3x=True) + compare_shader_materials(self, expected, actual) def test_shader_material_w3x_rgb_colors_roundtrip(self): - mesh = get_mesh(shader_mats=True) - mesh.shader_materials = [get_shader_material(w3x=True, rgb_colors=True)] + expected = get_shader_material(w3x=True, rgb_colors=True) - for source in mesh.shader_materials: - (material, _) = create_material_from_shader_material(self, mesh.name(), source) - principled = node_shader_utils.PrincipledBSDFWrapper(material, is_readonly=True) - actual = retrieve_shader_material(self, material, principled, w3x=True) + (material, _) = create_material_from_shader_material( + self, 'meshName', expected) + principled = node_shader_utils.PrincipledBSDFWrapper(material, is_readonly=True) + actual = retrieve_shader_material(self, material, principled, w3x=True) - for prop in source.properties: - if prop.name in ['ColorAmbient', 'ColorEmissive', 'ColorDiffuse', 'ColorSpecular']: - prop.type = 5 - prop.value = Vector((prop.value[0], prop.value[1], prop.value[2], 1.0)) + for prop in expected.properties: + if prop.name in ['ColorAmbient', 'ColorEmissive', 'ColorDiffuse', 'ColorSpecular']: + prop.type = 5 + prop.value = Vector((prop.value[0], prop.value[1], prop.value[2], 1.0)) - compare_shader_materials(self, source, actual) + compare_shader_materials(self, expected, actual) def test_shader_material_w3x_two_tex_roundtrip(self): - mesh = get_mesh(shader_mats=True) - mesh.shader_materials = [get_shader_material(w3x=True, two_tex=True)] + expected = get_shader_material(w3x=True, two_tex=True) - for source in mesh.shader_materials: - (material, _) = create_material_from_shader_material(self, mesh.name(), source) - principled = node_shader_utils.PrincipledBSDFWrapper(material, is_readonly=True) - actual = retrieve_shader_material(self, material, principled, w3x=True) - compare_shader_materials(self, source, actual) + (material, _) = create_material_from_shader_material( + self, 'meshName', expected) + principled = node_shader_utils.PrincipledBSDFWrapper(material, is_readonly=True) + actual = retrieve_shader_material(self, material, principled, w3x=True) + compare_shader_materials(self, expected, actual) def test_default_shader_material_properties_are_not_exported(self): - mesh = get_mesh(shader_mats=True) - mesh.shader_materials[0].properties = [] + expected = get_shader_material() + expected.properties = [] - (material, principled) = create_material_from_shader_material(self, mesh.name(), mesh.shader_materials[0]) + (material, principled) = create_material_from_shader_material(self, 'meshName', expected) actual = retrieve_shader_material(self, material, principled, w3x=False) self.assertEqual(0, len(actual.properties)) From fc88b24294cd0759a7dcaeafbabe7b5c737fc45f Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Mon, 10 Feb 2020 17:30:32 +0100 Subject: [PATCH 04/62] refactor vertex material creation --- io_mesh_w3d/common/utils/material_import.py | 3 + io_mesh_w3d/common/utils/mesh_import.py | 23 +-- tests/common/cases/test_utils.py | 143 ----------------- .../common/cases/utils/test_material_utils.py | 145 ++++++++++++++++++ 4 files changed, 153 insertions(+), 161 deletions(-) create mode 100644 tests/common/cases/utils/test_material_utils.py diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index ba537fd8..eb28a8c5 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -39,6 +39,9 @@ def create_vertex_material(context, principleds, structure, mesh, name, triangle tex = find_texture(context, texture.file, texture.id) principleds[mat_id].base_color_texture.image = tex + for i, shader in enumerate(struct.shaders): + set_shader_properties(materials[i], shader) + def create_material_from_vertex_material(name, vert_mat): name = name + "." + vert_mat.vm_name diff --git a/io_mesh_w3d/common/utils/mesh_import.py b/io_mesh_w3d/common/utils/mesh_import.py index b2942b16..560d447b 100644 --- a/io_mesh_w3d/common/utils/mesh_import.py +++ b/io_mesh_w3d/common/utils/mesh_import.py @@ -35,42 +35,29 @@ def create_mesh(context, mesh_struct, coll): # vertex material stuff name = mesh_struct.name() if mesh_struct.vert_materials: - materials = [] - create_vertex_material(context, principleds, materials, mesh_struct, mesh, name, triangles) - for i, shader in enumerate(mesh_struct.shaders): - set_shader_properties(materials[i], shader) + create_vertex_material(context, principleds, mesh_struct, mesh, name, triangles) if mesh_struct.prelit_unlit is not None: print('create prelit unlit') materials = [] prelit = mesh_struct.prelit_unlit - create_vertex_material(context, principleds, materials, prelit, mesh, name, triangles, prelit_type='PRELIT_UNLIT') - for i, shader in enumerate(prelit.shaders): - set_shader_properties(materials[i], shader) + create_vertex_material(context, principleds, prelit, mesh, name, triangles, prelit_type='PRELIT_UNLIT') if mesh_struct.prelit_vertex is not None: print('create prelit vertex') - materials = [] prelit = mesh_struct.prelit_vertex - create_vertex_material(context, principleds, materials, prelit, mesh, name, triangles, prelit_type='PRELIT_VERTEX') - for i, shader in enumerate(prelit.shaders): - set_shader_properties(materials[i], shader) + create_vertex_material(context, principleds, prelit, mesh, name, triangles, prelit_type='PRELIT_VERTEX') if mesh_struct.prelit_lightmap_multi_pass is not None: print('create prelit lightmap multi pass') - materials = [] prelit = mesh_struct.prelit_lightmap_multi_pass - create_vertex_material(context, principleds, materials, prelit, mesh, name, triangles, prelit_type='PRELIT_LIGHTMAP_MULTI_PASS') - for i, shader in enumerate(prelit.shaders): - set_shader_properties(materials[i], shader) + create_vertex_material(context, principleds, prelit, mesh, name, triangles, prelit_type='PRELIT_LIGHTMAP_MULTI_PASS') if mesh_struct.prelit_lightmap_multi_texture is not None: print('create prelit lightmap multi texture') materials = [] prelit = mesh_struct.prelit_lightmap_multi_texture - create_vertex_material(context, principleds, materials, prelit, mesh, name, triangles, prelit_type='PRELIT_LIGHTMAP_MULTI_TEXTURE') - for i, shader in enumerate(prelit.shaders): - set_shader_properties(materials[i], shader) + create_vertex_material(context, principleds, prelit, mesh, name, triangles, prelit_type='PRELIT_LIGHTMAP_MULTI_TEXTURE') # shader material stuff if mesh_struct.shader_materials: diff --git a/tests/common/cases/test_utils.py b/tests/common/cases/test_utils.py index 2a9a0d05..75f3702e 100644 --- a/tests/common/cases/test_utils.py +++ b/tests/common/cases/test_utils.py @@ -13,155 +13,12 @@ from tests.common.helpers.hierarchy import * from tests.common.helpers.hlod import * from tests.common.helpers.mesh import * -from tests.common.helpers.mesh_structs.shader_material import * from tests.utils import * from tests.w3d.helpers.compressed_animation import * from tests.w3d.helpers.dazzle import * -from tests.w3d.helpers.mesh_structs.shader import * -from tests.w3d.helpers.mesh_structs.vertex_material import * class TestUtils(TestCase): - def test_vertex_material_roundtrip(self): - expected = get_vertex_material() - - copyfile(up(up(self.relpath())) + '/testfiles/texture.dds', self.outpath() + 'texture.dds') - - (material, _) = create_material_from_vertex_material( - self, 'meshName', expected) - actual = retrieve_vertex_material(material) - compare_vertex_materials(self, expected, actual) - - def test_vertex_material_no_attributes_roundtrip(self): - expected = get_vertex_material() - - copyfile(up(up(self.relpath())) + '/testfiles/texture.dds', - self.outpath() + 'texture.dds') - - expected.vm_info.attributes = 0 - (material, _) = create_material_from_vertex_material( - self, 'meshName', expected) - actual = retrieve_vertex_material(material) - compare_vertex_materials(self, expected, actual) - - def test_shader_material_roundtrip(self): - expected = get_shader_material() - - copyfile(up(up(self.relpath())) + '/testfiles/texture.dds', self.outpath() + 'texture.dds') - - (material, _) = create_material_from_shader_material( - self, 'meshName', expected) - principled = node_shader_utils.PrincipledBSDFWrapper(material, is_readonly=True) - actual = retrieve_shader_material(material, principled) - compare_shader_materials(self, expected, actual) - - def test_duplicate_shader_material_roundtrip(self): - expecteds = [get_shader_material(), get_shader_material()] - - materials = [] - for mat in expecteds: - (material, _) = create_material_from_shader_material(self, 'meshName', mat) - materials.append(material) - - self.assertEqual(1, len(bpy.data.materials)) - self.assertTrue('meshName.NormalMapped.fx' in bpy.data.materials) - - for expected in expecteds: - principled = node_shader_utils.PrincipledBSDFWrapper(material, is_readonly=True) - actual = retrieve_shader_material(self, material, principled) - compare_shader_materials(self, expected, actual) - - def test_shader_material_w3x_roundtrip(self): - expected = get_shader_material(w3x=True) - copyfile(up(up(self.relpath())) + '/testfiles/texture.dds', - self.outpath() + 'texture.dds') - - (material, _) = create_material_from_shader_material( - self, 'meshName', expected) - principled = node_shader_utils.PrincipledBSDFWrapper(material, is_readonly=True) - actual = retrieve_shader_material(material, principled, w3x=True) - compare_shader_materials(self, expected, actual) - - def test_shader_material_w3x_rgb_colors_roundtrip(self): - expected = get_shader_material(w3x=True, rgb_colors=True) - - (material, _) = create_material_from_shader_material( - self, 'meshName', expected) - principled = node_shader_utils.PrincipledBSDFWrapper(material, is_readonly=True) - actual = retrieve_shader_material(self, material, principled, w3x=True) - - for prop in expected.properties: - if prop.name in ['ColorAmbient', 'ColorEmissive', 'ColorDiffuse', 'ColorSpecular']: - prop.type = 5 - prop.value = Vector((prop.value[0], prop.value[1], prop.value[2], 1.0)) - - compare_shader_materials(self, expected, actual) - - def test_shader_material_w3x_two_tex_roundtrip(self): - expected = get_shader_material(w3x=True, two_tex=True) - - (material, _) = create_material_from_shader_material( - self, 'meshName', expected) - principled = node_shader_utils.PrincipledBSDFWrapper(material, is_readonly=True) - actual = retrieve_shader_material(self, material, principled, w3x=True) - compare_shader_materials(self, expected, actual) - - def test_default_shader_material_properties_are_not_exported(self): - expected = get_shader_material() - expected.properties = [] - - (material, principled) = create_material_from_shader_material(self, 'meshName', expected) - - actual = retrieve_shader_material(self, material, principled, w3x=False) - self.assertEqual(0, len(actual.properties)) - - actual = retrieve_shader_material(self, material, principled, w3x=True) - self.assertEqual(0, len(actual.properties)) - - def test_shader_material_minimal_roundtrip(self): - mesh = get_mesh(shader_mats=True) - - for source in mesh.shader_materials: - source.properties = get_shader_material_properties_minimal() - - (material, principled) = create_material_from_shader_material(self, mesh.name(), source) - actual = retrieve_shader_material(self, material, principled) - source.properties[2].type = 5 - source.properties[2].value = get_vec4(x=1.0, y=0.2, z=0.33, w=1.0) - compare_shader_materials(self, source, actual) - - def test_shader_material_type_name_fallback(self): - mesh = get_mesh(shader_mats=True) - - for source in mesh.shader_materials: - source.header.type_name = 'LoremIpsum' - source.properties = [] - - (material, principled) = create_material_from_shader_material(self, mesh.name(), source) - actual = retrieve_shader_material(self, material, principled) - source.header.type_name = 'DefaultW3D.fx' - compare_shader_materials(self, source, actual) - - def test_shader_material_type_name_upgrade_to_normal_mapped(self): - mesh = get_mesh(shader_mats=True) - - for source in mesh.shader_materials: - source.header.type_name = 'LoremIpsum' - - (material, principled) = create_material_from_shader_material(self, mesh.name(), source) - actual = retrieve_shader_material(self, material, principled) - source.header.type_name = 'NormalMapped.fx' - compare_shader_materials(self, source, actual) - - def test_shader_roundtrip(self): - mesh = get_mesh() - - (material, _) = create_material_from_vertex_material(mesh.name(), mesh.vert_materials[0]) - expected = mesh.shaders[0] - set_shader_properties(material, expected) - actual = retrieve_shader(material) - compare_shaders(self, expected, actual) - def test_boxes_roundtrip(self): hlod = get_hlod() hlod.lod_arrays[0].sub_objects.append(get_hlod_sub_object(bone=1, name='containerName.WORLDBOX')) diff --git a/tests/common/cases/utils/test_material_utils.py b/tests/common/cases/utils/test_material_utils.py new file mode 100644 index 00000000..f16809cb --- /dev/null +++ b/tests/common/cases/utils/test_material_utils.py @@ -0,0 +1,145 @@ +# +# Written by Stephan Vedder and Michael Schnabel + +from tests.utils import TestCase +from shutil import copyfile +from os.path import dirname as up + +from io_mesh_w3d.common.utils.material_import import * +from io_mesh_w3d.common.utils.material_export import * + +from tests.w3d.helpers.mesh_structs.vertex_material import * +from tests.w3d.helpers.mesh_structs.shader import * +from tests.common.helpers.mesh_structs.shader_material import * + + +class TestMaterialUtils(TestCase): + def test_vertex_material_roundtrip(self): + expected = get_vertex_material() + + copyfile(up(up(up(self.relpath()))) + '/testfiles/texture.dds', + self.outpath() + 'texture.dds') + + (material, _) = create_material_from_vertex_material( + self, 'meshName', expected) + actual = retrieve_vertex_material(material) + compare_vertex_materials(self, expected, actual) + + def test_vertex_material_no_attributes_roundtrip(self): + expected = get_vertex_material() + + copyfile(up(up(up(self.relpath()))) + '/testfiles/texture.dds', + self.outpath() + 'texture.dds') + + expected.vm_info.attributes = 0 + (material, _) = create_material_from_vertex_material( + self, 'meshName', expected) + actual = retrieve_vertex_material(material) + compare_vertex_materials(self, expected, actual) + + def test_shader_material_roundtrip(self): + expected = get_shader_material() + + copyfile(up(up(up(self.relpath()))) + '/testfiles/texture.dds', + self.outpath() + 'texture.dds') + + (material, _) = create_material_from_shader_material( + self, 'meshName', expected) + principled = node_shader_utils.PrincipledBSDFWrapper(material, is_readonly=True) + actual = retrieve_shader_material(material, principled) + compare_shader_materials(self, expected, actual) + + def test_duplicate_shader_material_roundtrip(self): + expecteds = [get_shader_material(), get_shader_material()] + + materials = [] + for mat in expecteds: + (material, _) = create_material_from_shader_material(self, 'meshName', mat) + materials.append(material) + + self.assertEqual(1, len(bpy.data.materials)) + self.assertTrue('meshName.ShaderMaterial.fx' in bpy.data.materials) + + for expected in expecteds: + principled = node_shader_utils.PrincipledBSDFWrapper(material, is_readonly=True) + actual = retrieve_shader_material(material, principled) + compare_shader_materials(self, expected, actual) + + def test_shader_material_w3x_roundtrip(self): + expected = get_shader_material(w3x=True) + copyfile(up(up(up(self.relpath()))) + '/testfiles/texture.dds', + self.outpath() + 'texture.dds') + + (material, _) = create_material_from_shader_material( + self, 'meshName', expected) + principled = node_shader_utils.PrincipledBSDFWrapper(material, is_readonly=True) + actual = retrieve_shader_material(material, principled, w3x=True) + compare_shader_materials(self, expected, actual) + + def test_shader_material_w3x_rgb_colors_roundtrip(self): + expected = get_shader_material(w3x=True, rgb_colors=True) + copyfile(up(up(up(self.relpath()))) + '/testfiles/texture.dds', + self.outpath() + 'texture.dds') + + (material, _) = create_material_from_shader_material( + self, 'meshName', expected) + principled = node_shader_utils.PrincipledBSDFWrapper(material, is_readonly=True) + actual = retrieve_shader_material(material, principled, w3x=True) + + for prop in expected.properties: + if prop.name in ['ColorAmbient', 'ColorEmissive']: + prop.type = 5 + prop.value = RGBA(vec=prop.value, a=255) + elif prop.name in ['ColorDiffuse', 'ColorSpecular']: + prop.type = 5 + prop.value = RGBA(vec=prop.value, a=0) + + compare_shader_materials(self, expected, actual) + + def test_shader_material_w3x_two_tex_roundtrip(self): + expected = get_shader_material(w3x=True, two_tex=True) + copyfile(up(up(up(self.relpath()))) + '/testfiles/texture.dds', + self.outpath() + 'texture.dds') + + (material, _) = create_material_from_shader_material( + self, 'meshName', expected) + principled = node_shader_utils.PrincipledBSDFWrapper(material, is_readonly=True) + actual = retrieve_shader_material(material, principled, w3x=True) + compare_shader_materials(self, expected, actual) + + def test_default_shader_material_properties_are_not_exported(self): + expected = get_shader_material() + expected.properties = [] + + (material, principled) = create_material_from_shader_material(self, 'meshName', expected) + + actual = retrieve_shader_material(material, principled, w3x=False) + self.assertEqual(0, len(actual.properties)) + + actual = retrieve_shader_material(material, principled, w3x=True) + self.assertEqual(0, len(actual.properties)) + + def test_shader_material_minimal_roundtrip(self): + expected = get_shader_material() + expected.properties = [] + + copyfile(up(up(up(self.relpath()))) + '/testfiles/texture.dds', + self.outpath() + 'texture.dds') + + (material, principled) = create_material_from_shader_material( + self, 'meshName', expected) + actual = retrieve_shader_material(material, principled) + compare_shader_materials(self, expected, actual) + + def test_shader_roundtrip(self): + mat = get_vertex_material() + + copyfile(up(up(up(self.relpath()))) + '/testfiles/texture.dds', + self.outpath() + 'texture.dds') + + (material, _) = create_material_from_vertex_material( + self, 'meshName', mat) + expected = get_shader() + set_shader_properties(material, expected) + actual = retrieve_shader(material) + compare_shaders(self, expected, actual) \ No newline at end of file From 87364c881a069695facdd212d3288c1bc1b69d16 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Mon, 10 Feb 2020 17:42:12 +0100 Subject: [PATCH 05/62] refactor material creation --- io_mesh_w3d/common/utils/material_import.py | 16 +++++++++++- io_mesh_w3d/common/utils/mesh_import.py | 28 +++++---------------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index eb28a8c5..2e700f4d 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -17,13 +17,13 @@ def create_vertex_material(context, principleds, structure, mesh, name, triangle for vertMat in structure.vert_materials: (material, principled) = create_material_from_vertex_material(name, vertMat) mesh.materials.append(material) + materials.append(material) principleds.append(principled) if prelit_type is not None: material.material_type = 'PRELIT_MATERIAL' material.prelit_type = prelit_type - materials.append(material) b_mesh = bmesh.new() b_mesh.from_mesh(mesh) @@ -89,6 +89,20 @@ def create_material_from_vertex_material(name, vert_mat): # shader material ########################################################################## +def create_shader_materials(context, struct, mesh, triangles): + for i, shaderMat in enumerate(struct.shader_materials): + (material, principled) = create_material_from_shader_material( + context, mesh.name, shaderMat) + mesh.materials.append(material) + + if struct.material_passes: + b_mesh = bmesh.new() + b_mesh.from_mesh(mesh) + + for mat_pass in struct.material_passes: + create_uvlayer(context, mesh, b_mesh, triangles, mat_pass) + + def create_material_from_shader_material(context, name, shader_mat): name = name + '.' + shader_mat.header.type_name if name in bpy.data.materials: diff --git a/io_mesh_w3d/common/utils/mesh_import.py b/io_mesh_w3d/common/utils/mesh_import.py index 560d447b..092e4719 100644 --- a/io_mesh_w3d/common/utils/mesh_import.py +++ b/io_mesh_w3d/common/utils/mesh_import.py @@ -30,49 +30,33 @@ def create_mesh(context, mesh_struct, coll): if mesh_struct.is_hidden(): mesh_ob.hide_set(True) - principleds = [] - # vertex material stuff - name = mesh_struct.name() if mesh_struct.vert_materials: - create_vertex_material(context, principleds, mesh_struct, mesh, name, triangles) + create_vertex_materials(context, mesh_struct, mesh, triangles) if mesh_struct.prelit_unlit is not None: print('create prelit unlit') - materials = [] prelit = mesh_struct.prelit_unlit - create_vertex_material(context, principleds, prelit, mesh, name, triangles, prelit_type='PRELIT_UNLIT') + create_vertex_materials(context, prelit, mesh, triangles, prelit_type='PRELIT_UNLIT') if mesh_struct.prelit_vertex is not None: print('create prelit vertex') prelit = mesh_struct.prelit_vertex - create_vertex_material(context, principleds, prelit, mesh, name, triangles, prelit_type='PRELIT_VERTEX') + create_vertex_materials(context, prelit, mesh, triangles, prelit_type='PRELIT_VERTEX') if mesh_struct.prelit_lightmap_multi_pass is not None: print('create prelit lightmap multi pass') prelit = mesh_struct.prelit_lightmap_multi_pass - create_vertex_material(context, principleds, prelit, mesh, name, triangles, prelit_type='PRELIT_LIGHTMAP_MULTI_PASS') + create_vertex_materials(context, prelit, mesh, triangles, prelit_type='PRELIT_LIGHTMAP_MULTI_PASS') if mesh_struct.prelit_lightmap_multi_texture is not None: print('create prelit lightmap multi texture') - materials = [] prelit = mesh_struct.prelit_lightmap_multi_texture - create_vertex_material(context, principleds, prelit, mesh, name, triangles, prelit_type='PRELIT_LIGHTMAP_MULTI_TEXTURE') + create_vertex_materials(context, prelit, mesh, triangles, prelit_type='PRELIT_LIGHTMAP_MULTI_TEXTURE') # shader material stuff if mesh_struct.shader_materials: - for i, shaderMat in enumerate(mesh_struct.shader_materials): - (material, principled) = create_material_from_shader_material( - context, mesh_struct.name(), shaderMat) - mesh.materials.append(material) - principleds.append(principled) - - b_mesh = None - for mat_pass in mesh_struct.material_passes: - if b_mesh is None: - b_mesh = bmesh.new() - b_mesh.from_mesh(mesh) - create_uvlayer(context, mesh, b_mesh, triangles, mat_pass) + create_shader_materials(context, mesh_struct, mesh, triangles) def rig_mesh(mesh_struct, hierarchy, rig, sub_object=None): From cbee5eaffc4cd5d6618b94ff18481a4bbec1f394 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Tue, 11 Feb 2020 09:57:37 +0100 Subject: [PATCH 06/62] material creation refactoring --- io_mesh_w3d/common/utils/mesh_import.py | 34 +++++-------------------- 1 file changed, 7 insertions(+), 27 deletions(-) diff --git a/io_mesh_w3d/common/utils/mesh_import.py b/io_mesh_w3d/common/utils/mesh_import.py index 092e4719..80ef4670 100644 --- a/io_mesh_w3d/common/utils/mesh_import.py +++ b/io_mesh_w3d/common/utils/mesh_import.py @@ -30,33 +30,13 @@ def create_mesh(context, mesh_struct, coll): if mesh_struct.is_hidden(): mesh_ob.hide_set(True) - # vertex material stuff - if mesh_struct.vert_materials: - create_vertex_materials(context, mesh_struct, mesh, triangles) - - if mesh_struct.prelit_unlit is not None: - print('create prelit unlit') - prelit = mesh_struct.prelit_unlit - create_vertex_materials(context, prelit, mesh, triangles, prelit_type='PRELIT_UNLIT') - - if mesh_struct.prelit_vertex is not None: - print('create prelit vertex') - prelit = mesh_struct.prelit_vertex - create_vertex_materials(context, prelit, mesh, triangles, prelit_type='PRELIT_VERTEX') - - if mesh_struct.prelit_lightmap_multi_pass is not None: - print('create prelit lightmap multi pass') - prelit = mesh_struct.prelit_lightmap_multi_pass - create_vertex_materials(context, prelit, mesh, triangles, prelit_type='PRELIT_LIGHTMAP_MULTI_PASS') - - if mesh_struct.prelit_lightmap_multi_texture is not None: - print('create prelit lightmap multi texture') - prelit = mesh_struct.prelit_lightmap_multi_texture - create_vertex_materials(context, prelit, mesh, triangles, prelit_type='PRELIT_LIGHTMAP_MULTI_TEXTURE') - - # shader material stuff - if mesh_struct.shader_materials: - create_shader_materials(context, mesh_struct, mesh, triangles) + create_shader_materials(context, mesh_struct, mesh, triangles) + + create_vertex_materials(context, mesh_struct, mesh, triangles) + create_vertex_materials(context, mesh_struct.prelit_unlit, mesh, triangles, prelit_type='PRELIT_UNLIT') + create_vertex_materials(context, mesh_struct.prelit_vertex, mesh, triangles, prelit_type='PRELIT_VERTEX') + create_vertex_materials(context, mesh_struct.prelit_lightmap_multi_pass, mesh, triangles, prelit_type='PRELIT_LIGHTMAP_MULTI_PASS') + create_vertex_materials(context, mesh_struct.prelit_lightmap_multi_texture, mesh, triangles, prelit_type='PRELIT_LIGHTMAP_MULTI_TEXTURE') def rig_mesh(mesh_struct, hierarchy, rig, sub_object=None): From 87aeec1fdf08c017d7334941a1e746d3f54d1446 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Wed, 12 Feb 2020 17:32:44 +0100 Subject: [PATCH 07/62] added some shader material stuff --- io_mesh_w3d/common/utils/NodeShaderWrapper.py | 67 +++++++++++++++++++ io_mesh_w3d/common/utils/material_import.py | 1 - io_mesh_w3d/common/utils/mesh_export.py | 5 ++ .../common/cases/utils/test_material_utils.py | 7 +- tests/w3d/cases/test_roundtrip.py | 3 + 5 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 io_mesh_w3d/common/utils/NodeShaderWrapper.py diff --git a/io_mesh_w3d/common/utils/NodeShaderWrapper.py b/io_mesh_w3d/common/utils/NodeShaderWrapper.py new file mode 100644 index 00000000..71ef2b55 --- /dev/null +++ b/io_mesh_w3d/common/utils/NodeShaderWrapper.py @@ -0,0 +1,67 @@ +# +# Written by Stephan Vedder and Michael Schnabel + +import bpy + + +def get_material_shader(material): + return material.get('shader', None) + +def get_material_textures(material): + textures = dict() + + node_tree = material.node_tree + nodes = node_tree.nodes + # ... + +def create_texture_node(node_tree, tex_path): + node = node_tree.nodes.new('ShaderNodeTexImage') + node.name = 'TestTexture' + + node.color = (1, 0, 0) + node.use_custom_color = True + + node.alpha_mode = 'CHANNEL_PACKED' + + node.image = image + return node + +def set_node_position(node, x, y): + node.location = Vector((x * 300.0, y * -300.0)) + +def create_shader(name): + shader = bpy.data.materials.new(name) + #shader['shader'] = ?? + + shader.use_nodes = True + shader.use_backface_culling = True + shader.shadow_method = 'CLIP' + shader.blend_method = 'CLIP' + + node_tree = shader.node_tree + nodes = node_tree.nodes + links = node_tree.links + + shader_root = nodes.get('Principled BSDF') + + diffuse_tex = create_texture_node(node_tree, name) + set_node_pos(diffuse_tex, -5, 0) + + links.new(diffuse_tex.outputs['Color'], shader_root.inputs['Base Color']) + links.new(albedo_texture.outputs['Alpha'], shader_root.inputs['Alpha']) + + #specular + + #separate_rgb = node_tree.nodes.new(type="ShaderNodeSeparateRGB") + #set_node_pos(separate_rgb, -4, 1) + #links.new(material_texture.outputs['Color'], separate_rgb.inputs['Image']) + # links.new(separate_rgb.outputs['R'], shader_root.inputs['Specular']) # material.R used for custom mask? + #links.new(separate_rgb.outputs['G'], shader_root.inputs['Specular']) + #links.new(separate_rgb.outputs['B'], shader_root.inputs['Metallic']) + #links.new(material_texture.outputs['Alpha'], shader_root.inputs['Roughness']) + + # normal + + normal_texture.image.colorspace_settings.is_data = True + + return shader \ No newline at end of file diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index 2e700f4d..9a053e07 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -24,7 +24,6 @@ def create_vertex_material(context, principleds, structure, mesh, name, triangle material.material_type = 'PRELIT_MATERIAL' material.prelit_type = prelit_type - b_mesh = bmesh.new() b_mesh.from_mesh(mesh) diff --git a/io_mesh_w3d/common/utils/mesh_export.py b/io_mesh_w3d/common/utils/mesh_export.py index 1d141af0..7bfa4c86 100644 --- a/io_mesh_w3d/common/utils/mesh_export.py +++ b/io_mesh_w3d/common/utils/mesh_export.py @@ -185,6 +185,7 @@ def retrieve_meshes(context, hierarchy, rig, container_name, force_vertex_materi if material.material_type == 'VERTEX_MATERIAL': mat_pass.shader_ids = [i] mat_pass.vertex_material_ids = [i] + mat_pass.tx_stages[0].tx_ids = [0] mesh_struct.shaders.append(shader) mesh_struct.vert_materials.append(vert_material) mesh_struct.material_passes.append(mat_pass) @@ -201,6 +202,7 @@ def retrieve_meshes(context, hierarchy, rig, container_name, force_vertex_materi material_passes=[], textures=[]) + mat_pass.tx_stages[0].tx_ids = [0] mat_pass.shader_ids = [len(mesh_struct.prelit_unlit.shaders)] mat_pass.vertex_material_ids = [len(mesh_struct.prelit_unlit.vert_materials)] mesh_struct.prelit_unlit.shaders.append(shader) @@ -217,6 +219,7 @@ def retrieve_meshes(context, hierarchy, rig, container_name, force_vertex_materi material_passes=[], textures=[]) + mat_pass.tx_stages[0].tx_ids = [0] mat_pass.shader_ids = [len(mesh_struct.prelit_vertex.shaders)] mat_pass.vertex_material_ids = [len(mesh_struct.prelit_vertex.vert_materials)] mesh_struct.prelit_vertex.shaders.append(shader) @@ -233,6 +236,7 @@ def retrieve_meshes(context, hierarchy, rig, container_name, force_vertex_materi material_passes=[], textures=[]) + mat_pass.tx_stages[0].tx_ids = [0] mat_pass.shader_ids = [len(mesh_struct.prelit_lightmap_multi_pass.shaders)] mat_pass.vertex_material_ids = [len(mesh_struct.prelit_lightmap_multi_pass.vert_materials)] mesh_struct.prelit_lightmap_multi_pass.shaders.append(shader) @@ -249,6 +253,7 @@ def retrieve_meshes(context, hierarchy, rig, container_name, force_vertex_materi material_passes=[], textures=[]) + mat_pass.tx_stages[0].tx_ids = [0] mat_pass.shader_ids = [len(mesh_struct.prelit_lightmap_multi_texture.shaders)] mat_pass.vertex_material_ids = [len(mesh_struct.prelit_lightmap_multi_texture.vert_materials)] mesh_struct.prelit_lightmap_multi_texture.shaders.append(shader) diff --git a/tests/common/cases/utils/test_material_utils.py b/tests/common/cases/utils/test_material_utils.py index f16809cb..b4819f0f 100644 --- a/tests/common/cases/utils/test_material_utils.py +++ b/tests/common/cases/utils/test_material_utils.py @@ -87,12 +87,9 @@ def test_shader_material_w3x_rgb_colors_roundtrip(self): actual = retrieve_shader_material(material, principled, w3x=True) for prop in expected.properties: - if prop.name in ['ColorAmbient', 'ColorEmissive']: + if prop.name in ['ColorAmbient', 'ColorEmissive', 'ColorDiffuse', 'ColorSpecular']: prop.type = 5 - prop.value = RGBA(vec=prop.value, a=255) - elif prop.name in ['ColorDiffuse', 'ColorSpecular']: - prop.type = 5 - prop.value = RGBA(vec=prop.value, a=0) + prop.value = Vector((prop.value[0], prop.value[1], prop.value[2], 1.0)) compare_shader_materials(self, expected, actual) diff --git a/tests/w3d/cases/test_roundtrip.py b/tests/w3d/cases/test_roundtrip.py index 51f6ff48..66501b4b 100644 --- a/tests/w3d/cases/test_roundtrip.py +++ b/tests/w3d/cases/test_roundtrip.py @@ -248,6 +248,8 @@ def test_roundtrip_HAM_tc_animation(self): self.assertTrue('Brakelight' in bpy.data.objects) def test_roundtrip_prelit(self): + self.enable_logging() + print('############### roundtrip test') hierarchy_name = 'testhiera_skl' hierarchy = get_hierarchy(hierarchy_name) meshes = [get_mesh(name='sword', skin=True, prelit=True), @@ -269,6 +271,7 @@ def test_roundtrip_prelit(self): # import self.filepath = self.outpath() + 'output.w3d' load(self) + print('########################### test done') # check created objects self.assertTrue('output' in bpy.data.objects) From 7077c672bde3375b5d98bbed536b2e4579c1e3a9 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Wed, 12 Feb 2020 20:27:34 +0100 Subject: [PATCH 08/62] initial work on better shader setup --- io_mesh_w3d/common/utils/NodeShaderWrapper.py | 1 - io_mesh_w3d/common/utils/material_import.py | 78 ++++++++++++++++--- 2 files changed, 68 insertions(+), 11 deletions(-) diff --git a/io_mesh_w3d/common/utils/NodeShaderWrapper.py b/io_mesh_w3d/common/utils/NodeShaderWrapper.py index 71ef2b55..63f53512 100644 --- a/io_mesh_w3d/common/utils/NodeShaderWrapper.py +++ b/io_mesh_w3d/common/utils/NodeShaderWrapper.py @@ -3,7 +3,6 @@ import bpy - def get_material_shader(material): return material.get('shader', None) diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index 9a053e07..ef19db7b 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -9,6 +9,33 @@ from io_mesh_w3d.w3d.structs.mesh_structs.vertex_material import * +def set_node_position(node, x, y): + node.location = Vector((x, y)) + +def create_texture_node(node_tree, texture): + node = node_tree.nodes.new('ShaderNodeTexImage') + node.name = 'TestTexture' + #node.color = (1, 0, 0) + #node.use_custom_color = True + #node.alpha_mode = 'CHANNEL_PACKED' + node.image = texture + return node + +def create_uv_map_node(node_tree): + node = node_tree.nodes.new('ShaderNodeUVMap') + node.name = 'Test' + + #node.uv_map = 'uvmapname' + return node + +def create_rgb_mix_node(node_tree): + node = node_tree.nodes.new('ShaderNodeMixRGB') + #node.blend_type + #node.use_alpha + #node.use_clamp + return node + + ########################################################################## # vertex material ########################################################################## @@ -30,13 +57,41 @@ def create_vertex_material(context, principleds, structure, mesh, name, triangle for mat_pass in structure.material_passes: create_uvlayer(context, mesh, b_mesh, triangles, mat_pass) + for mat_pass in struct.material_passes: if mat_pass.tx_stages: tx_stage = mat_pass.tx_stages[0] mat_id = mat_pass.vertex_material_ids[0] tex_id = tx_stage.tx_ids[0] - texture = structure.textures[tex_id] - tex = find_texture(context, texture.file, texture.id) - principleds[mat_id].base_color_texture.image = tex + + node_tree = materials[mat_id].node_tree + links = node_tree.links + + mix_node = create_rgb_mix_node(node_tree) + mix_node.location = Vector((-200, 290)) + links.new(mix_node.outputs['Color'], principleds[mat_id].inputs['Base Color']) + + texture_struct = struct.textures[tex_id] + texture = find_texture(context, texture_struct.file, texture_struct.id) + + texture_node = create_texture_node(node_tree, texture) + texture_node.location = Vector((-600, 290)) + links.new(texture_node.outputs['Color'], mix_node.inputs['Color1']) + links.new(texture_node.outputs['Alpha'], principleds[mat_id].inputs['Alpha']) + + create_uvlayer(context, mesh, b_mesh, triangles, mat_pass) + uv_node = create_uv_map_node(node_tree) + uv_node.location = Vector((-650, 290)) + links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) + + texture2_node = create_texture_node(node_tree, None) #diffuse2 + texture2_node.location = Vector((-600, 190)) + links.new(texture2_node.outputs['Color'], mix_node.inputs['Color2']) + links.new(texture2_node.outputs['Alpha'], mix_node.inputs['Fac']) + + create_uvlayer(context, mesh, b_mesh, triangles, mat_pass) + uv2_node = create_uv_map_node(node_tree) + uv2_node.location = Vector((-650, 190)) + links.new(uv2_node.outputs['UV'], texture2_node.inputs['Vector']) for i, shader in enumerate(struct.shaders): set_shader_properties(materials[i], shader) @@ -46,12 +101,13 @@ def create_material_from_vertex_material(name, vert_mat): name = name + "." + vert_mat.vm_name if name in bpy.data.materials: material = bpy.data.materials[name] - principled = node_shader_utils.PrincipledBSDFWrapper(material, is_readonly=False) - return material, principled + principled_bsdf = material.node_tree.nodes.get('Principled BSDF') + return material, principled_bsdf material = bpy.data.materials.new(name) material.material_type = 'VERTEX_MATERIAL' material.use_nodes = True + material.shadow_method = 'CLIP' material.blend_method = 'BLEND' material.show_transparent_back = False @@ -66,11 +122,12 @@ def create_material_from_vertex_material(name, vert_mat): if attribs & DEPTH_CUE_TO_ALPHA: attributes.add('DEPTH_CUE_TO_ALPHA') - principled = node_shader_utils.PrincipledBSDFWrapper(material, is_readonly=False) - principled.base_color = vert_mat.vm_info.diffuse.to_vector_rgb() - principled.alpha = vert_mat.vm_info.opacity + material.attributes = atts - material.attributes = attributes + principled_bsdf = material.node_tree.nodes.get('Principled BSDF') + #principled_bsdf.base_color = vert_mat.vm_info.diffuse.to_vector_rgb() + #principled_bsdf.alpha = vert_mat.vm_info.opacity + material.specular_intensity = vert_mat.vm_info.shininess material.specular_color = vert_mat.vm_info.specular.to_vector_rgb() material.emission = vert_mat.vm_info.emissive.to_vector_rgba() @@ -81,7 +138,7 @@ def create_material_from_vertex_material(name, vert_mat): material.vm_args_0 = vert_mat.vm_args_0 material.vm_args_1 = vert_mat.vm_args_1 - return material, principled + return material, principled_bsdf ########################################################################## @@ -112,6 +169,7 @@ def create_material_from_shader_material(context, name, shader_mat): material = bpy.data.materials.new(name) material.material_type = 'SHADER_MATERIAL' material.use_nodes = True + shader.shadow_method = 'CLIP' material.blend_method = 'BLEND' material.show_transparent_back = False From c26097b307d243608ec1929af7bec8f0dfe6a484 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Wed, 12 Feb 2020 21:30:58 +0100 Subject: [PATCH 09/62] added normal map texture --- io_mesh_w3d/common/utils/material_import.py | 78 +++++++++++++++++---- 1 file changed, 63 insertions(+), 15 deletions(-) diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index ef19db7b..ac0ec575 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -9,32 +9,61 @@ from io_mesh_w3d.w3d.structs.mesh_structs.vertex_material import * -def set_node_position(node, x, y): - node.location = Vector((x, y)) + #node.color = (1, 0, 0) + #node.use_custom_color = True + #node.name = 'Test' def create_texture_node(node_tree, texture): + # inputs: Vector + # outputs: Color, Alpha + node = node_tree.nodes.new('ShaderNodeTexImage') - node.name = 'TestTexture' - #node.color = (1, 0, 0) - #node.use_custom_color = True - #node.alpha_mode = 'CHANNEL_PACKED' + #node.color_mapping + #node.extension # interpolation past bounds node.image = texture + #node.image_user + #node.interpolation + #node.projection + #node.projection_blend + #node.texture_mapping return node def create_uv_map_node(node_tree): - node = node_tree.nodes.new('ShaderNodeUVMap') - node.name = 'Test' + # outputs: UV + node = node_tree.nodes.new('ShaderNodeUVMap') #node.uv_map = 'uvmapname' return node def create_rgb_mix_node(node_tree): + # inputs: Fac, Color1, Color2 + # outputs: Color + node = node_tree.nodes.new('ShaderNodeMixRGB') #node.blend_type #node.use_alpha #node.use_clamp return node +def create_normal_map_node(node_tree): + # inputs: Strength, Color + # outputs: Normal + + node = node_tree.nodes.new('ShaderNodeNormalMap') + node.space = 'TANGENT' + #node.uv_map = 'uvmapname' + return node + + +def create_uvlayer2(tx_coords, mesh, b_mesh, triangles, name): + uv_layer = mesh.uv_layers.new(do_init=False) + uv_layer.name = name + for i, face in enumerate(b_mesh.faces): + for loop in face.loops: + idx = triangles[i][loop.index % 3] + uv_layer.data[loop.index].uv = tx_coords[idx].xy + return name + ########################################################################## # vertex material @@ -67,32 +96,52 @@ def create_vertex_material(context, principleds, structure, mesh, name, triangle links = node_tree.links mix_node = create_rgb_mix_node(node_tree) - mix_node.location = Vector((-200, 290)) + mix_node.location = Vector((-200, 350)) links.new(mix_node.outputs['Color'], principleds[mat_id].inputs['Base Color']) texture_struct = struct.textures[tex_id] texture = find_texture(context, texture_struct.file, texture_struct.id) texture_node = create_texture_node(node_tree, texture) - texture_node.location = Vector((-600, 290)) + texture_node.location = Vector((-600, 600)) links.new(texture_node.outputs['Color'], mix_node.inputs['Color1']) links.new(texture_node.outputs['Alpha'], principleds[mat_id].inputs['Alpha']) - create_uvlayer(context, mesh, b_mesh, triangles, mat_pass) uv_node = create_uv_map_node(node_tree) - uv_node.location = Vector((-650, 290)) + uv_node.uv_map = create_uvlayer2(mat_pass.tx_stages[0].tx_coords, mesh, b_mesh, triangles, 'diffuse') + uv_node.location = Vector((-900, 400)) links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) texture2_node = create_texture_node(node_tree, None) #diffuse2 - texture2_node.location = Vector((-600, 190)) + texture2_node.location = Vector((-600, 200)) links.new(texture2_node.outputs['Color'], mix_node.inputs['Color2']) links.new(texture2_node.outputs['Alpha'], mix_node.inputs['Fac']) create_uvlayer(context, mesh, b_mesh, triangles, mat_pass) uv2_node = create_uv_map_node(node_tree) - uv2_node.location = Vector((-650, 190)) + uv2_node.uv_map = create_uvlayer2(mat_pass.tx_stages[0].tx_coords, mesh, b_mesh, triangles, 'diffuse2') + uv2_node.location = Vector((-900, 200)) links.new(uv2_node.outputs['UV'], texture2_node.inputs['Vector']) + + + + normal_map_node = create_normal_map_node(node_tree) + normal_map_node.location = Vector((-200, -100)) + links.new(normal_map_node.outputs['Normal'], principleds[mat_id].inputs['Normal']) + + texture_normal_node = create_texture_node(node_tree, None) #normal + texture_normal_node.location = Vector((-600, -100)) + links.new(texture_normal_node.outputs['Color'], normal_map_node.inputs['Color']) + links.new(texture_normal_node.outputs['Alpha'], normal_map_node.inputs['Strength']) + + create_uvlayer(context, mesh, b_mesh, triangles, mat_pass) + uv3_node = create_uv_map_node(node_tree) + uv3_node.uv_map = create_uvlayer2(mat_pass.tx_stages[0].tx_coords, mesh, b_mesh, triangles, 'normal') + uv3_node.location = Vector((-900, -100)) + links.new(uv3_node.outputs['UV'], texture_normal_node.inputs['Vector']) + + for i, shader in enumerate(struct.shaders): set_shader_properties(materials[i], shader) @@ -169,7 +218,6 @@ def create_material_from_shader_material(context, name, shader_mat): material = bpy.data.materials.new(name) material.material_type = 'SHADER_MATERIAL' material.use_nodes = True - shader.shadow_method = 'CLIP' material.blend_method = 'BLEND' material.show_transparent_back = False From fbc426ee72de3c59b31438098b8de2a8a235d9f9 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Wed, 12 Feb 2020 22:09:47 +0100 Subject: [PATCH 10/62] added specular texture --- io_mesh_w3d/common/utils/material_import.py | 30 ++++++++++++--------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index ac0ec575..d498a5af 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -96,49 +96,53 @@ def create_vertex_material(context, principleds, structure, mesh, name, triangle links = node_tree.links mix_node = create_rgb_mix_node(node_tree) - mix_node.location = Vector((-200, 350)) + mix_node.location = Vector((-250, 400)) links.new(mix_node.outputs['Color'], principleds[mat_id].inputs['Base Color']) texture_struct = struct.textures[tex_id] texture = find_texture(context, texture_struct.file, texture_struct.id) texture_node = create_texture_node(node_tree, texture) - texture_node.location = Vector((-600, 600)) + texture_node.location = Vector((-550, 600)) links.new(texture_node.outputs['Color'], mix_node.inputs['Color1']) links.new(texture_node.outputs['Alpha'], principleds[mat_id].inputs['Alpha']) uv_node = create_uv_map_node(node_tree) uv_node.uv_map = create_uvlayer2(mat_pass.tx_stages[0].tx_coords, mesh, b_mesh, triangles, 'diffuse') - uv_node.location = Vector((-900, 400)) + uv_node.location = Vector((-750, 600)) links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) - texture2_node = create_texture_node(node_tree, None) #diffuse2 - texture2_node.location = Vector((-600, 200)) + texture2_node = create_texture_node(node_tree, None) + texture2_node.location = Vector((-550, 300)) links.new(texture2_node.outputs['Color'], mix_node.inputs['Color2']) links.new(texture2_node.outputs['Alpha'], mix_node.inputs['Fac']) - create_uvlayer(context, mesh, b_mesh, triangles, mat_pass) uv2_node = create_uv_map_node(node_tree) uv2_node.uv_map = create_uvlayer2(mat_pass.tx_stages[0].tx_coords, mesh, b_mesh, triangles, 'diffuse2') - uv2_node.location = Vector((-900, 200)) + uv2_node.location = Vector((-750, 300)) links.new(uv2_node.outputs['UV'], texture2_node.inputs['Vector']) + texture_spec_node = create_texture_node(node_tree, None) + texture_spec_node.location = Vector((-550, 0)) + links.new(texture_spec_node.outputs['Color'], principleds[mat_id].inputs['Specular']) - + uv_spec_node = create_uv_map_node(node_tree) + uv_spec_node.uv_map = create_uvlayer2(mat_pass.tx_stages[0].tx_coords, mesh, b_mesh, triangles, 'specular') + uv_spec_node.location = Vector((-750, 0)) + links.new(uv_spec_node.outputs['UV'], texture_spec_node.inputs['Vector']) normal_map_node = create_normal_map_node(node_tree) - normal_map_node.location = Vector((-200, -100)) + normal_map_node.location = Vector((-250, -300)) links.new(normal_map_node.outputs['Normal'], principleds[mat_id].inputs['Normal']) - texture_normal_node = create_texture_node(node_tree, None) #normal - texture_normal_node.location = Vector((-600, -100)) + texture_normal_node = create_texture_node(node_tree, None) + texture_normal_node.location = Vector((-550, -300)) links.new(texture_normal_node.outputs['Color'], normal_map_node.inputs['Color']) links.new(texture_normal_node.outputs['Alpha'], normal_map_node.inputs['Strength']) - create_uvlayer(context, mesh, b_mesh, triangles, mat_pass) uv3_node = create_uv_map_node(node_tree) uv3_node.uv_map = create_uvlayer2(mat_pass.tx_stages[0].tx_coords, mesh, b_mesh, triangles, 'normal') - uv3_node.location = Vector((-900, -100)) + uv3_node.location = Vector((-750, -300)) links.new(uv3_node.outputs['UV'], texture_normal_node.inputs['Vector']) From 6763feafc27a783ebaf5a5bbb86f059b5ec197d4 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Thu, 13 Feb 2020 10:20:38 +0100 Subject: [PATCH 11/62] added emission color, hide unsupported shader inputs --- io_mesh_w3d/common/utils/material_import.py | 60 +++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index d498a5af..6a7e65c4 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -12,6 +12,26 @@ #node.color = (1, 0, 0) #node.use_custom_color = True #node.name = 'Test' + #node.label + + +def get_connected_nodes(links, node, input, types=[]): + nodes = [] + for link in links: + #print(link.to_node) + #print(link.to_socket) + if link.to_node == node and link.to_socket.identifier == input: + # and link.from_socket in outputs: + # and type(node) == bpy.types.ShaderNodeTexture.... + # and node.inputs[''].is_linked + nodes.append(link.from_node) + + for node in nodes: + print('###') + print(node.bl_idname) + print(node.name) + return nodes + def create_texture_node(node_tree, texture): # inputs: Vector @@ -54,6 +74,19 @@ def create_normal_map_node(node_tree): #node.uv_map = 'uvmapname' return node +def create_seperate_hsv_node(node_tree): + # inputs: Color + # outputs: H, S, V + + node = node_tree.nodes.new('ShaderNodeSeperateHSV') + return node + +def create_rgb_node(node_tree): + # outputs: Color + + node = node_tree.nodes.new('ShaderNodeRGB') + return node + def create_uvlayer2(tx_coords, mesh, b_mesh, triangles, name): uv_layer = mesh.uv_layers.new(do_init=False) @@ -92,6 +125,25 @@ def create_vertex_material(context, principleds, structure, mesh, name, triangle mat_id = mat_pass.vertex_material_ids[0] tex_id = tx_stage.tx_ids[0] + # hide unsupported inputs + principleds[mat_id].inputs['Subsurface'].hide = True + principleds[mat_id].inputs['Subsurface Radius'].hide = True + principleds[mat_id].inputs['Subsurface Color'].hide = True + principleds[mat_id].inputs['Metallic'].hide = True + principleds[mat_id].inputs['Specular Tint'].hide = True + principleds[mat_id].inputs['Roughness'].hide = True + principleds[mat_id].inputs['Anisotropic'].hide = True + principleds[mat_id].inputs['Anisotropic Rotation'].hide = True + principleds[mat_id].inputs['Sheen'].hide = True + principleds[mat_id].inputs['Sheen Tint'].hide = True + principleds[mat_id].inputs['Clearcoat'].hide = True + principleds[mat_id].inputs['Clearcoat Roughness'].hide = True + principleds[mat_id].inputs['IOR'].hide = True + principleds[mat_id].inputs['Transmission'].hide = True + principleds[mat_id].inputs['Transmission Roughness'].hide = True + principleds[mat_id].inputs['Clearcoat Normal'].hide = True + principleds[mat_id].inputs['Tangent'].hide = True + node_tree = materials[mat_id].node_tree links = node_tree.links @@ -131,6 +183,10 @@ def create_vertex_material(context, principleds, structure, mesh, name, triangle uv_spec_node.location = Vector((-750, 0)) links.new(uv_spec_node.outputs['UV'], texture_spec_node.inputs['Vector']) + emission_color_node = create_rgb_node(node_tree) + emission_color_node.location = Vector((-250, -100)) + links.new(emission_color_node.outputs['Color'], principleds[mat_id].inputs['Emission']) + normal_map_node = create_normal_map_node(node_tree) normal_map_node.location = Vector((-250, -300)) links.new(normal_map_node.outputs['Normal'], principleds[mat_id].inputs['Normal']) @@ -146,6 +202,10 @@ def create_vertex_material(context, principleds, structure, mesh, name, triangle links.new(uv3_node.outputs['UV'], texture_normal_node.inputs['Vector']) + get_connected_nodes(links, principleds[mat_id], 'Base Color') + get_connected_nodes(links, principleds[mat_id], 'Specular') + + for i, shader in enumerate(struct.shaders): set_shader_properties(materials[i], shader) From 9ed235ddd62562a1bf6b3596ee814a2e1aeb2a09 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Thu, 13 Feb 2020 13:15:51 +0100 Subject: [PATCH 12/62] node group creation --- io_mesh_w3d/common/utils/material_import.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index 6a7e65c4..039f58a7 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -15,6 +15,23 @@ #node.label +def create_node_group(): + group = bpy.data.node_groups.new('name', 'ShaderNodeTree') + + # create group inputs + group_inputs = test_group.nodes.new('NodeGroupInput') + group_inputs.location = (-350,0) + test_group.inputs.new('NodeSocketFloat','in_to_greater') + test_group.inputs.new('NodeSocketFloat','in_to_less') + + # create group outputs + group_outputs = test_group.nodes.new('NodeGroupOutput') + group_outputs.location = (300,0) + test_group.outputs.new('NodeSocketFloat','out_result') + + #TODO link those inputs and outputs to outer scope + + def get_connected_nodes(links, node, input, types=[]): nodes = [] for link in links: From 24088c3291260cd1ec786ce52b72b1512c6c933d Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Mon, 17 Feb 2020 17:09:33 +0100 Subject: [PATCH 13/62] some work on node group creation --- io_mesh_w3d/common/utils/material_import.py | 62 ++++++++++++++++++--- 1 file changed, 54 insertions(+), 8 deletions(-) diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index 039f58a7..121d4ab2 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -15,21 +15,46 @@ #node.label -def create_node_group(): - group = bpy.data.node_groups.new('name', 'ShaderNodeTree') +def create_material_pass(): + material = bpy.data.materials.new('meshName.MaterialPass1') + + material.material_type = 'VERTEX_MATERIAL' + material.use_nodes = True + material.shadow_method = 'CLIP' + material.blend_method = 'BLEND' + material.show_transparent_back = False + + # delete principled bsdf + principled_bsdf = material.node_tree.nodes.get('Principled BSDF') + material.node_tree.nodes.remove(principled_bsdf) + + # get or create node group + + +def create_material_node_group(nodes, name): + group = bpy.data.node_groups.new(name, 'ShaderNodeTree') + node_tree = group + links = node_tree.links + # create nodes + shader = create_specular_shader_node(node_tree) # create group inputs - group_inputs = test_group.nodes.new('NodeGroupInput') + group_inputs = group.nodes.new('NodeGroupInput') group_inputs.location = (-350,0) - test_group.inputs.new('NodeSocketFloat','in_to_greater') - test_group.inputs.new('NodeSocketFloat','in_to_less') + group.inputs.new('NodeSocketFloat', 'in_to_greater') + group.inputs.new('NodeSocketFloat', 'in_to_less') # create group outputs - group_outputs = test_group.nodes.new('NodeGroupOutput') + group_outputs = group.nodes.new('NodeGroupOutput') group_outputs.location = (300,0) - test_group.outputs.new('NodeSocketFloat','out_result') + group.outputs.new('NodeSocketFloat', 'BSDF_out') + + links.new(shader.outputs['BSDF'], group_outputs.inputs['BSDF_out']) + + inst = nodes.new(type='ShaderNodeGroup') + inst.node_tree = group + return inst - #TODO link those inputs and outputs to outer scope def get_connected_nodes(links, node, input, types=[]): @@ -50,6 +75,21 @@ def get_connected_nodes(links, node, input, types=[]): return nodes +def create_specular_shader_node(node_tree): + # inputs: Base Color, Specular, Roughness, Emissive Color, Transparency, + # Normal, Clear Coat, Clear Coat Radius, Clear Coat Normal, Ambient Occlusion + # outputs: BSDF + + node = node_tree.nodes.new('ShaderNodeEeveeSpecular') + node.label = 'Shader' + # hide unused inputs + node.inputs['Clear Coat'].hide = True + node.inputs['Clear Coat Roughness'].hide = True + node.inputs['Clear Coat Normal'].hide = True + node.inputs['Ambient Occlusion'].hide = True + return node + + def create_texture_node(node_tree, texture): # inputs: Vector # outputs: Color, Alpha @@ -164,6 +204,12 @@ def create_vertex_material(context, principleds, structure, mesh, name, triangle node_tree = materials[mat_id].node_tree links = node_tree.links + create_material_node_group(node_tree.nodes, 'VertexMaterial1') + + #shade = create_specular_shader_node(node_tree) + #out = node_tree.nodes.get('Material Output') + #links.new(shade.outputs['BSDF'], out.inputs['Surface']) + mix_node = create_rgb_mix_node(node_tree) mix_node.location = Vector((-250, 400)) links.new(mix_node.outputs['Color'], principleds[mat_id].inputs['Base Color']) From 4fe8b3d51fb7de361b4166dcfb2ca9e1f90ce2e8 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Mon, 17 Feb 2020 23:39:20 +0100 Subject: [PATCH 14/62] material node group creation --- io_mesh_w3d/__init__.py | 7 +++ io_mesh_w3d/common/utils/material_import.py | 64 +++++++++++++++++---- 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/io_mesh_w3d/__init__.py b/io_mesh_w3d/__init__.py index 2431d9c0..f6787229 100644 --- a/io_mesh_w3d/__init__.py +++ b/io_mesh_w3d/__init__.py @@ -1,6 +1,7 @@ # # Written by Stephan Vedder and Michael Schnabel +import bpy from bpy_extras.io_utils import ImportHelper, ExportHelper from io_mesh_w3d.export_utils import save from io_mesh_w3d.custom_properties import * @@ -406,6 +407,12 @@ def register(): bpy.types.TOPBAR_MT_file_import.append(menu_func_import) bpy.types.TOPBAR_MT_file_export.append(menu_func_export) + import time + from threading import Timer + from io_mesh_w3d.common.utils.material_import import register_w3d_material_node_group + + Timer(1, register_w3d_material_node_group, ()).start() + def unregister(): for class_ in reversed(CLASSES): diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index 121d4ab2..d184e7e9 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -31,25 +31,56 @@ def create_material_pass(): # get or create node group -def create_material_node_group(nodes, name): - group = bpy.data.node_groups.new(name, 'ShaderNodeTree') +def register_w3d_material_node_group(): + group = bpy.data.node_groups.new('W3DMaterial', 'ShaderNodeTree') node_tree = group links = node_tree.links - # create nodes - shader = create_specular_shader_node(node_tree) # create group inputs group_inputs = group.nodes.new('NodeGroupInput') group_inputs.location = (-350,0) - group.inputs.new('NodeSocketFloat', 'in_to_greater') - group.inputs.new('NodeSocketFloat', 'in_to_less') + group.inputs.new('NodeSocketColor', 'Diffuse') + group.inputs.new('NodeSocketFloat', 'Alpha') + group.inputs['Alpha'].default_value = 1.0 + group.inputs.new('NodeSocketColor', 'Diffuse2') + group.inputs.new('NodeSocketFloat', 'Factor') + group.inputs.new('NodeSocketColor', 'Specular') + group.inputs.new('NodeSocketFloat', 'Roughness') + group.inputs.new('NodeSocketColor', 'Emissive') + group.inputs.new('NodeSocketVector', 'Normal') + group.inputs.new('NodeSocketFloat', 'Strength') # create group outputs group_outputs = group.nodes.new('NodeGroupOutput') group_outputs.location = (300,0) - group.outputs.new('NodeSocketFloat', 'BSDF_out') + group.outputs.new('NodeSocketShader', 'BSDF') + + # create and link nodes + mix = create_rgb_mix_node(node_tree) + mix.location = (-100, 200) + links.new(group_inputs.outputs['Diffuse'], mix.inputs['Color1']) + links.new(group_inputs.outputs['Diffuse2'], mix.inputs['Color2']) + links.new(group_inputs.outputs['Factor'], mix.inputs['Fac']) + + subtract = create_math_node(node_tree, mode='SUBTRACT') + subtract.location = (-100, 0) + subtract.inputs[0].default_value = 1.0 + links.new(group_inputs.outputs['Alpha'], subtract.inputs[1]) - links.new(shader.outputs['BSDF'], group_outputs.inputs['BSDF_out']) + normal = create_normal_map_node(node_tree) + normal.location = (-100, -200) + links.new(group_inputs.outputs['Normal'], normal.inputs['Color']) + links.new(group_inputs.outputs['Strength'], normal.inputs['Strength']) + + shader = create_specular_shader_node(node_tree) + shader.location = (100, 0) + links.new(mix.outputs['Color'], shader.inputs['Base Color']) + links.new(group_inputs.outputs['Specular'], shader.inputs['Specular']) + links.new(group_inputs.outputs['Roughness'], shader.inputs['Roughness']) + links.new(group_inputs.outputs['Emissive'], shader.inputs['Emissive Color']) + links.new(subtract.outputs['Value'], shader.inputs['Transparency']) + links.new(normal.outputs['Normal'], shader.inputs['Normal']) + links.new(shader.outputs['BSDF'], group_outputs.inputs['BSDF']) inst = nodes.new(type='ShaderNodeGroup') inst.node_tree = group @@ -112,6 +143,15 @@ def create_uv_map_node(node_tree): #node.uv_map = 'uvmapname' return node +def create_math_node(node_tree, mode='SUBTRACT'): + # inputs: Value, Value + # outputs: Value + + node = node_tree.nodes.new('ShaderNodeMath') + node.operation = mode + #node.clamp = False + return node + def create_rgb_mix_node(node_tree): # inputs: Fac, Color1, Color2 # outputs: Color @@ -204,11 +244,11 @@ def create_vertex_material(context, principleds, structure, mesh, name, triangle node_tree = materials[mat_id].node_tree links = node_tree.links - create_material_node_group(node_tree.nodes, 'VertexMaterial1') - #shade = create_specular_shader_node(node_tree) - #out = node_tree.nodes.get('Material Output') - #links.new(shade.outputs['BSDF'], out.inputs['Surface']) + inst = node_tree.nodes.new(type='ShaderNodeGroup') + inst.node_tree = bpy.data.node_groups['W3DMaterial'] + inst.label = struct.vert_materials[mat_id].vm_name + mix_node = create_rgb_mix_node(node_tree) mix_node.location = Vector((-250, 400)) From fa0b24b1b0d7737247433c280cdafadaf4e8641e Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Mon, 17 Feb 2020 23:42:16 +0100 Subject: [PATCH 15/62] set material pass index --- io_mesh_w3d/common/utils/material_import.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index d184e7e9..f8a096f9 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -15,14 +15,15 @@ #node.label -def create_material_pass(): - material = bpy.data.materials.new('meshName.MaterialPass1') +def create_material_pass(index=1): + material = bpy.data.materials.new('meshName.MaterialPass' + str(index)) material.material_type = 'VERTEX_MATERIAL' material.use_nodes = True material.shadow_method = 'CLIP' material.blend_method = 'BLEND' material.show_transparent_back = False + material.pass_index = index # delete principled bsdf principled_bsdf = material.node_tree.nodes.get('Principled BSDF') From 578c6d42124386bc20abd54d5c0f4ef819a1b244 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Mon, 17 Feb 2020 23:57:36 +0100 Subject: [PATCH 16/62] link node group instead of principled bsdf --- io_mesh_w3d/common/utils/material_import.py | 34 +++++++++------------ 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index f8a096f9..2f745e88 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -48,7 +48,7 @@ def register_w3d_material_node_group(): group.inputs.new('NodeSocketColor', 'Specular') group.inputs.new('NodeSocketFloat', 'Roughness') group.inputs.new('NodeSocketColor', 'Emissive') - group.inputs.new('NodeSocketVector', 'Normal') + group.inputs.new('NodeSocketColor', 'Normal') group.inputs.new('NodeSocketFloat', 'Strength') # create group outputs @@ -250,18 +250,17 @@ def create_vertex_material(context, principleds, structure, mesh, name, triangle inst.node_tree = bpy.data.node_groups['W3DMaterial'] inst.label = struct.vert_materials[mat_id].vm_name - - mix_node = create_rgb_mix_node(node_tree) - mix_node.location = Vector((-250, 400)) - links.new(mix_node.outputs['Color'], principleds[mat_id].inputs['Base Color']) + output = node_tree.nodes.get('Material Output') + links.new(inst.outputs['BSDF'], output.inputs['Surface']) + texture_struct = struct.textures[tex_id] texture = find_texture(context, texture_struct.file, texture_struct.id) texture_node = create_texture_node(node_tree, texture) texture_node.location = Vector((-550, 600)) - links.new(texture_node.outputs['Color'], mix_node.inputs['Color1']) - links.new(texture_node.outputs['Alpha'], principleds[mat_id].inputs['Alpha']) + links.new(texture_node.outputs['Color'], inst.inputs['Diffuse']) + links.new(texture_node.outputs['Alpha'], inst.inputs['Alpha']) uv_node = create_uv_map_node(node_tree) uv_node.uv_map = create_uvlayer2(mat_pass.tx_stages[0].tx_coords, mesh, b_mesh, triangles, 'diffuse') @@ -270,8 +269,8 @@ def create_vertex_material(context, principleds, structure, mesh, name, triangle texture2_node = create_texture_node(node_tree, None) texture2_node.location = Vector((-550, 300)) - links.new(texture2_node.outputs['Color'], mix_node.inputs['Color2']) - links.new(texture2_node.outputs['Alpha'], mix_node.inputs['Fac']) + links.new(texture2_node.outputs['Color'], inst.inputs['Diffuse2']) + links.new(texture2_node.outputs['Alpha'], inst.inputs['Factor']) uv2_node = create_uv_map_node(node_tree) uv2_node.uv_map = create_uvlayer2(mat_pass.tx_stages[0].tx_coords, mesh, b_mesh, triangles, 'diffuse2') @@ -280,7 +279,7 @@ def create_vertex_material(context, principleds, structure, mesh, name, triangle texture_spec_node = create_texture_node(node_tree, None) texture_spec_node.location = Vector((-550, 0)) - links.new(texture_spec_node.outputs['Color'], principleds[mat_id].inputs['Specular']) + links.new(texture_spec_node.outputs['Color'], inst.inputs['Specular']) uv_spec_node = create_uv_map_node(node_tree) uv_spec_node.uv_map = create_uvlayer2(mat_pass.tx_stages[0].tx_coords, mesh, b_mesh, triangles, 'specular') @@ -289,25 +288,20 @@ def create_vertex_material(context, principleds, structure, mesh, name, triangle emission_color_node = create_rgb_node(node_tree) emission_color_node.location = Vector((-250, -100)) - links.new(emission_color_node.outputs['Color'], principleds[mat_id].inputs['Emission']) - - normal_map_node = create_normal_map_node(node_tree) - normal_map_node.location = Vector((-250, -300)) - links.new(normal_map_node.outputs['Normal'], principleds[mat_id].inputs['Normal']) + links.new(emission_color_node.outputs['Color'], inst.inputs['Emissive']) texture_normal_node = create_texture_node(node_tree, None) texture_normal_node.location = Vector((-550, -300)) - links.new(texture_normal_node.outputs['Color'], normal_map_node.inputs['Color']) - links.new(texture_normal_node.outputs['Alpha'], normal_map_node.inputs['Strength']) + links.new(texture_normal_node.outputs['Color'], inst.inputs['Normal']) + links.new(texture_normal_node.outputs['Alpha'], inst.inputs['Strength']) uv3_node = create_uv_map_node(node_tree) uv3_node.uv_map = create_uvlayer2(mat_pass.tx_stages[0].tx_coords, mesh, b_mesh, triangles, 'normal') uv3_node.location = Vector((-750, -300)) links.new(uv3_node.outputs['UV'], texture_normal_node.inputs['Vector']) - - get_connected_nodes(links, principleds[mat_id], 'Base Color') - get_connected_nodes(links, principleds[mat_id], 'Specular') + get_connected_nodes(links, inst, 'Diffuse') + get_connected_nodes(links, inst, 'Specular') for i, shader in enumerate(struct.shaders): From f9a481fa338bd96a1dec293be8f66751432cf9c9 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Tue, 18 Feb 2020 10:24:01 +0100 Subject: [PATCH 17/62] annotation --- io_mesh_w3d/__init__.py | 1 + io_mesh_w3d/common/utils/material_import.py | 1 + 2 files changed, 2 insertions(+) diff --git a/io_mesh_w3d/__init__.py b/io_mesh_w3d/__init__.py index f6787229..347cbe83 100644 --- a/io_mesh_w3d/__init__.py +++ b/io_mesh_w3d/__init__.py @@ -407,6 +407,7 @@ def register(): bpy.types.TOPBAR_MT_file_import.append(menu_func_import) bpy.types.TOPBAR_MT_file_export.append(menu_func_export) + # workaround to register the node group when the addon is active import time from threading import Timer from io_mesh_w3d.common.utils.material_import import register_w3d_material_node_group diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index 2f745e88..ec219aba 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -50,6 +50,7 @@ def register_w3d_material_node_group(): group.inputs.new('NodeSocketColor', 'Emissive') group.inputs.new('NodeSocketColor', 'Normal') group.inputs.new('NodeSocketFloat', 'Strength') + group.inputs.new('NodeSocketBool', 'Strength2') # create group outputs group_outputs = group.nodes.new('NodeGroupOutput') From da624a43bcf660f5ec69a383e2f6d9bca0f9636e Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Tue, 18 Feb 2020 22:18:11 +0100 Subject: [PATCH 18/62] create alpha pipeline --- io_mesh_w3d/__init__.py | 4 +- io_mesh_w3d/common/utils/material_import.py | 84 ++++++++++++++++----- 2 files changed, 69 insertions(+), 19 deletions(-) diff --git a/io_mesh_w3d/__init__.py b/io_mesh_w3d/__init__.py index 347cbe83..6d8ded34 100644 --- a/io_mesh_w3d/__init__.py +++ b/io_mesh_w3d/__init__.py @@ -410,11 +410,13 @@ def register(): # workaround to register the node group when the addon is active import time from threading import Timer - from io_mesh_w3d.common.utils.material_import import register_w3d_material_node_group + from io_mesh_w3d.common.utils.material_import import register_w3d_material_node_group, register_alpha_node_group + Timer(1, register_alpha_node_group, ()).start() Timer(1, register_w3d_material_node_group, ()).start() + def unregister(): for class_ in reversed(CLASSES): bpy.utils.unregister_class(class_) diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index ec219aba..36fa245a 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -44,13 +44,17 @@ def register_w3d_material_node_group(): group.inputs.new('NodeSocketFloat', 'Alpha') group.inputs['Alpha'].default_value = 1.0 group.inputs.new('NodeSocketColor', 'Diffuse2') - group.inputs.new('NodeSocketFloat', 'Factor') + group.inputs.new('NodeSocketFloat', 'Alpha2') + group.inputs.new('NodeSocketInt', 'DestBlend') + group.inputs['DestBlend'].default_value = 0 + group.inputs['DestBlend'].min_value = 0 + group.inputs['DestBlend'].max_value = 1 group.inputs.new('NodeSocketColor', 'Specular') group.inputs.new('NodeSocketFloat', 'Roughness') group.inputs.new('NodeSocketColor', 'Emissive') group.inputs.new('NodeSocketColor', 'Normal') group.inputs.new('NodeSocketFloat', 'Strength') - group.inputs.new('NodeSocketBool', 'Strength2') + # create group outputs group_outputs = group.nodes.new('NodeGroupOutput') @@ -62,12 +66,14 @@ def register_w3d_material_node_group(): mix.location = (-100, 200) links.new(group_inputs.outputs['Diffuse'], mix.inputs['Color1']) links.new(group_inputs.outputs['Diffuse2'], mix.inputs['Color2']) - links.new(group_inputs.outputs['Factor'], mix.inputs['Fac']) + links.new(group_inputs.outputs['Alpha2'], mix.inputs['Fac']) - subtract = create_math_node(node_tree, mode='SUBTRACT') - subtract.location = (-100, 0) - subtract.inputs[0].default_value = 1.0 - links.new(group_inputs.outputs['Alpha'], subtract.inputs[1]) + alpha_pipeline = node_tree.nodes.new(type='ShaderNodeGroup') + alpha_pipeline.location = (-100, 0) + alpha_pipeline.node_tree = bpy.data.node_groups['W3DAlphaPipeline'] + links.new(group_inputs.outputs['Diffuse'], alpha_pipeline.inputs['Diffuse']) + links.new(group_inputs.outputs['Alpha'], alpha_pipeline.inputs['Alpha']) + links.new(group_inputs.outputs['DestBlend'], alpha_pipeline.inputs['DestBlend']) normal = create_normal_map_node(node_tree) normal.location = (-100, -200) @@ -80,14 +86,61 @@ def register_w3d_material_node_group(): links.new(group_inputs.outputs['Specular'], shader.inputs['Specular']) links.new(group_inputs.outputs['Roughness'], shader.inputs['Roughness']) links.new(group_inputs.outputs['Emissive'], shader.inputs['Emissive Color']) - links.new(subtract.outputs['Value'], shader.inputs['Transparency']) + links.new(alpha_pipeline.outputs['Alpha'], shader.inputs['Transparency']) links.new(normal.outputs['Normal'], shader.inputs['Normal']) links.new(shader.outputs['BSDF'], group_outputs.inputs['BSDF']) - inst = nodes.new(type='ShaderNodeGroup') - inst.node_tree = group - return inst +def register_alpha_node_group(): + group = bpy.data.node_groups.new('W3DAlphaPipeline', 'ShaderNodeTree') + node_tree = group + links = node_tree.links + + # create group inputs + group_inputs = group.nodes.new('NodeGroupInput') + group_inputs.location = (-500,0) + group.inputs.new('NodeSocketColor', 'Diffuse') + group.inputs.new('NodeSocketFloat', 'Alpha') + group.inputs['Alpha'].default_value = 1.0 + group.inputs.new('NodeSocketInt', 'DestBlend') + group.inputs['DestBlend'].default_value = 0 + group.inputs['DestBlend'].min_value = 0 + group.inputs['DestBlend'].max_value = 1 + + # create group outputs + group_outputs = group.nodes.new('NodeGroupOutput') + group_outputs.location = (500,0) + group.outputs.new('NodeSocketFloat', 'Alpha') + + # default texture alpha + compare_1 = create_math_node(node_tree, mode='COMPARE') + compare_1.location = (-200, 100) + compare_1.inputs[0].default_value = 0 + links.new(group_inputs.outputs['DestBlend'], compare_1.inputs[1]) + links.new(group_inputs.outputs['Alpha'], compare_1.inputs[2]) + + # v of diffuse + seperate_hsv = create_seperate_hsv_node(node_tree) + seperate_hsv.location = (-300, -100) + links.new(group_inputs.outputs['Diffuse'], seperate_hsv.inputs['Color']) + + compare_2 = create_math_node(node_tree, mode='COMPARE') + compare_2.location = (-100, -100) + compare_2.inputs[0].default_value = 1 + links.new(group_inputs.outputs['DestBlend'], compare_2.inputs[1]) + links.new(seperate_hsv.outputs['V'], compare_2.inputs[2]) + + # both + add_node = create_math_node(node_tree, mode='ADD') + add_node.location = (100, 0) + links.new(compare_1.outputs['Value'], add_node.inputs[0]) + links.new(compare_2.outputs['Value'], add_node.inputs[1]) + + subtract_node = create_math_node(node_tree, mode='SUBTRACT') + subtract_node.location = (300, 0) + subtract_node.inputs[0].default_value = 1.0 + links.new(add_node.outputs['Value'], subtract_node.inputs[1]) + links.new(subtract_node.outputs['Value'], group_outputs.inputs['Alpha']) def get_connected_nodes(links, node, input, types=[]): @@ -177,7 +230,7 @@ def create_seperate_hsv_node(node_tree): # inputs: Color # outputs: H, S, V - node = node_tree.nodes.new('ShaderNodeSeperateHSV') + node = node_tree.nodes.new('ShaderNodeSeparateHSV') return node def create_rgb_node(node_tree): @@ -246,7 +299,6 @@ def create_vertex_material(context, principleds, structure, mesh, name, triangle node_tree = materials[mat_id].node_tree links = node_tree.links - inst = node_tree.nodes.new(type='ShaderNodeGroup') inst.node_tree = bpy.data.node_groups['W3DMaterial'] inst.label = struct.vert_materials[mat_id].vm_name @@ -271,7 +323,7 @@ def create_vertex_material(context, principleds, structure, mesh, name, triangle texture2_node = create_texture_node(node_tree, None) texture2_node.location = Vector((-550, 300)) links.new(texture2_node.outputs['Color'], inst.inputs['Diffuse2']) - links.new(texture2_node.outputs['Alpha'], inst.inputs['Factor']) + links.new(texture2_node.outputs['Alpha'], inst.inputs['Alpha2']) uv2_node = create_uv_map_node(node_tree) uv2_node.uv_map = create_uvlayer2(mat_pass.tx_stages[0].tx_coords, mesh, b_mesh, triangles, 'diffuse2') @@ -287,10 +339,6 @@ def create_vertex_material(context, principleds, structure, mesh, name, triangle uv_spec_node.location = Vector((-750, 0)) links.new(uv_spec_node.outputs['UV'], texture_spec_node.inputs['Vector']) - emission_color_node = create_rgb_node(node_tree) - emission_color_node.location = Vector((-250, -100)) - links.new(emission_color_node.outputs['Color'], inst.inputs['Emissive']) - texture_normal_node = create_texture_node(node_tree, None) texture_normal_node.location = Vector((-550, -300)) links.new(texture_normal_node.outputs['Color'], inst.inputs['Normal']) From 7d6436439be5c38b57b7470529b31f8dfc416560 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Tue, 18 Feb 2020 22:24:07 +0100 Subject: [PATCH 19/62] fixed vertex material creation --- io_mesh_w3d/common/utils/material_import.py | 39 ++++++--------------- 1 file changed, 11 insertions(+), 28 deletions(-) diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index 36fa245a..73dd3c0e 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -277,76 +277,59 @@ def create_vertex_material(context, principleds, structure, mesh, name, triangle mat_id = mat_pass.vertex_material_ids[0] tex_id = tx_stage.tx_ids[0] - # hide unsupported inputs - principleds[mat_id].inputs['Subsurface'].hide = True - principleds[mat_id].inputs['Subsurface Radius'].hide = True - principleds[mat_id].inputs['Subsurface Color'].hide = True - principleds[mat_id].inputs['Metallic'].hide = True - principleds[mat_id].inputs['Specular Tint'].hide = True - principleds[mat_id].inputs['Roughness'].hide = True - principleds[mat_id].inputs['Anisotropic'].hide = True - principleds[mat_id].inputs['Anisotropic Rotation'].hide = True - principleds[mat_id].inputs['Sheen'].hide = True - principleds[mat_id].inputs['Sheen Tint'].hide = True - principleds[mat_id].inputs['Clearcoat'].hide = True - principleds[mat_id].inputs['Clearcoat Roughness'].hide = True - principleds[mat_id].inputs['IOR'].hide = True - principleds[mat_id].inputs['Transmission'].hide = True - principleds[mat_id].inputs['Transmission Roughness'].hide = True - principleds[mat_id].inputs['Clearcoat Normal'].hide = True - principleds[mat_id].inputs['Tangent'].hide = True - node_tree = materials[mat_id].node_tree links = node_tree.links + node_tree.nodes.remove(principleds[mat_id]) + inst = node_tree.nodes.new(type='ShaderNodeGroup') + inst.location = (0, 300) inst.node_tree = bpy.data.node_groups['W3DMaterial'] inst.label = struct.vert_materials[mat_id].vm_name output = node_tree.nodes.get('Material Output') links.new(inst.outputs['BSDF'], output.inputs['Surface']) - texture_struct = struct.textures[tex_id] texture = find_texture(context, texture_struct.file, texture_struct.id) texture_node = create_texture_node(node_tree, texture) - texture_node.location = Vector((-550, 600)) + texture_node.location = (-550, 600) links.new(texture_node.outputs['Color'], inst.inputs['Diffuse']) links.new(texture_node.outputs['Alpha'], inst.inputs['Alpha']) uv_node = create_uv_map_node(node_tree) uv_node.uv_map = create_uvlayer2(mat_pass.tx_stages[0].tx_coords, mesh, b_mesh, triangles, 'diffuse') - uv_node.location = Vector((-750, 600)) + uv_node.location = (-750, 600) links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) texture2_node = create_texture_node(node_tree, None) - texture2_node.location = Vector((-550, 300)) + texture2_node.location = (-550, 300) links.new(texture2_node.outputs['Color'], inst.inputs['Diffuse2']) links.new(texture2_node.outputs['Alpha'], inst.inputs['Alpha2']) uv2_node = create_uv_map_node(node_tree) uv2_node.uv_map = create_uvlayer2(mat_pass.tx_stages[0].tx_coords, mesh, b_mesh, triangles, 'diffuse2') - uv2_node.location = Vector((-750, 300)) + uv2_node.location = (-750, 300) links.new(uv2_node.outputs['UV'], texture2_node.inputs['Vector']) texture_spec_node = create_texture_node(node_tree, None) - texture_spec_node.location = Vector((-550, 0)) + texture_spec_node.location = (-550, 0) links.new(texture_spec_node.outputs['Color'], inst.inputs['Specular']) uv_spec_node = create_uv_map_node(node_tree) uv_spec_node.uv_map = create_uvlayer2(mat_pass.tx_stages[0].tx_coords, mesh, b_mesh, triangles, 'specular') - uv_spec_node.location = Vector((-750, 0)) + uv_spec_node.location = (-750, 0) links.new(uv_spec_node.outputs['UV'], texture_spec_node.inputs['Vector']) texture_normal_node = create_texture_node(node_tree, None) - texture_normal_node.location = Vector((-550, -300)) + texture_normal_node.location = (-550, -300) links.new(texture_normal_node.outputs['Color'], inst.inputs['Normal']) links.new(texture_normal_node.outputs['Alpha'], inst.inputs['Strength']) uv3_node = create_uv_map_node(node_tree) uv3_node.uv_map = create_uvlayer2(mat_pass.tx_stages[0].tx_coords, mesh, b_mesh, triangles, 'normal') - uv3_node.location = Vector((-750, -300)) + uv3_node.location = (-750, -300) links.new(uv3_node.outputs['UV'], texture_normal_node.inputs['Vector']) get_connected_nodes(links, inst, 'Diffuse') From 4a3ad0cbecb4067bc2960e24f146e8bdd66efa26 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Tue, 18 Feb 2020 23:41:26 +0100 Subject: [PATCH 20/62] small changes --- io_mesh_w3d/common/utils/material_import.py | 1 + 1 file changed, 1 insertion(+) diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index 73dd3c0e..458eab26 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -285,6 +285,7 @@ def create_vertex_material(context, principleds, structure, mesh, name, triangle inst = node_tree.nodes.new(type='ShaderNodeGroup') inst.location = (0, 300) inst.node_tree = bpy.data.node_groups['W3DMaterial'] + inst.inputs['DestBlend'].link_limit = 0 inst.label = struct.vert_materials[mat_id].vm_name output = node_tree.nodes.get('Material Output') From 8a89db7d14c1370c4b65c7cb431d5b266be0f403 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Wed, 19 Feb 2020 16:44:05 +0100 Subject: [PATCH 21/62] some work on material pass creation --- io_mesh_w3d/__init__.py | 17 +-- io_mesh_w3d/common/utils/material_import.py | 118 ++++++++++++++++++-- tests/utils.py | 9 +- 3 files changed, 127 insertions(+), 17 deletions(-) diff --git a/io_mesh_w3d/__init__.py b/io_mesh_w3d/__init__.py index 6d8ded34..0ca9f9c3 100644 --- a/io_mesh_w3d/__init__.py +++ b/io_mesh_w3d/__init__.py @@ -318,11 +318,9 @@ def draw(self, context): col = layout.column() col.prop(mat.shader, 'alpha_test') col = layout.column() - col.prop(mat.shader, - 'post_detail_color_func') + col.prop(mat.shader,'post_detail_color_func') col = layout.column() - col.prop(mat.shader, - 'post_detail_alpha_func') + col.prop(mat.shader,'post_detail_alpha_func') else: col = layout.column() @@ -398,6 +396,11 @@ def draw(self, context): ) +def register_node_groups(): + from io_mesh_w3d.common.utils.material_import import register_w3d_material_node_group + register_w3d_material_node_group() + + def register(): for class_ in CLASSES: bpy.utils.register_class(class_) @@ -410,11 +413,8 @@ def register(): # workaround to register the node group when the addon is active import time from threading import Timer - from io_mesh_w3d.common.utils.material_import import register_w3d_material_node_group, register_alpha_node_group - - Timer(1, register_alpha_node_group, ()).start() - Timer(1, register_w3d_material_node_group, ()).start() + Timer(1, register_node_groups, ()).start() def unregister(): @@ -426,3 +426,4 @@ def unregister(): if __name__ == '__main__': register() + register_node_groups() diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index 458eab26..ad05d240 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -15,7 +15,34 @@ #node.label -def create_material_pass(index=1): +def create_material_passes(base_struct): + for i, mat_pass in enumerate(base_struct.material_passes): + vert_materials = [] + shaders = [] + textures = [] + shader_materials = [] + tx_coords = [] + + for vert_mat_id in mat_pass.vertex_material_ids: + vert_materials.append(base_struct.vert_materials[vert_mat_id]) + + for shader_id in mat_pass.shader_ids: + shaders.append(base_struct.shaders[shader_id]) + + for tx_stage in mat_pass.tx_stages: + textures.append(base_struct.textures[tx_stage.tx_ids[0]]) + tx_coords.append(tx_stage.tx_coords) + + for shader_mat_id in mat_pass.shader_material_ids: + shader_materials.append(base_struct.shader_materials[shader_mat_id]) + + tx_coords.append(mat_pass.tx_coords) + + create_material_pass(ver_materials, shaders, textures, shader_materials, tx_coords, i + 1) + + +def create_material_pass(vert_materials, shaders, textures, shader_materials, tx_coords, index=1): + # TODO: support case where there is only one vertex material and multiple textures? material = bpy.data.materials.new('meshName.MaterialPass' + str(index)) material.material_type = 'VERTEX_MATERIAL' @@ -25,11 +52,72 @@ def create_material_pass(index=1): material.show_transparent_back = False material.pass_index = index + # get or create node group + node_tree = materials.node_tree + links = node_tree.links + # delete principled bsdf - principled_bsdf = material.node_tree.nodes.get('Principled BSDF') - material.node_tree.nodes.remove(principled_bsdf) + principled_bsdf = node_tree.nodes.get('Principled BSDF') + node_tree.nodes.remove(principled_bsdf) + + # create material node (vert_mat, shader) , (shader_mat) + # create texture nodes + + +def create_shading_pipeline(vert_material, shader, textures, shader_material, tx_coords, index=1): + inst = node_tree.nodes.new(type='ShaderNodeGroup') + inst.location = (0, 300) + inst.node_tree = bpy.data.node_groups['W3DMaterial'] + inst.label = struct.vert_materials[mat_id].vm_name + + output = node_tree.nodes.get('Material Output') + links.new(inst.outputs['BSDF'], output.inputs['Surface']) + + texture_struct = struct.textures[tex_id] + texture = find_texture(context, texture_struct.file, texture_struct.id) + + texture_node = create_texture_node(node_tree, texture) + texture_node.location = (-550, 600) + links.new(texture_node.outputs['Color'], inst.inputs['Diffuse']) + links.new(texture_node.outputs['Alpha'], inst.inputs['Alpha']) + + uv_node = create_uv_map_node(node_tree) + uv_node.uv_map = create_uvlayer2(mat_pass.tx_stages[0].tx_coords, mesh, b_mesh, triangles, 'diffuse') + uv_node.location = (-750, 600) + links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) + + texture2_node = create_texture_node(node_tree, None) + texture2_node.location = (-550, 300) + links.new(texture2_node.outputs['Color'], inst.inputs['Diffuse2']) + links.new(texture2_node.outputs['Alpha'], inst.inputs['Alpha2']) + + uv2_node = create_uv_map_node(node_tree) + uv2_node.uv_map = create_uvlayer2(mat_pass.tx_stages[0].tx_coords, mesh, b_mesh, triangles, 'diffuse2') + uv2_node.location = (-750, 300) + links.new(uv2_node.outputs['UV'], texture2_node.inputs['Vector']) + + texture_spec_node = create_texture_node(node_tree, None) + texture_spec_node.location = (-550, 0) + links.new(texture_spec_node.outputs['Color'], inst.inputs['Specular']) + + uv_spec_node = create_uv_map_node(node_tree) + uv_spec_node.uv_map = create_uvlayer2(mat_pass.tx_stages[0].tx_coords, mesh, b_mesh, triangles, 'specular') + uv_spec_node.location = (-750, 0) + links.new(uv_spec_node.outputs['UV'], texture_spec_node.inputs['Vector']) + + texture_normal_node = create_texture_node(node_tree, None) + texture_normal_node.location = (-550, -300) + links.new(texture_normal_node.outputs['Color'], inst.inputs['Normal']) + links.new(texture_normal_node.outputs['Alpha'], inst.inputs['Strength']) + + uv3_node = create_uv_map_node(node_tree) + uv3_node.uv_map = create_uvlayer2(mat_pass.tx_stages[0].tx_coords, mesh, b_mesh, triangles, 'normal') + uv3_node.location = (-750, -300) + links.new(uv3_node.outputs['UV'], texture_normal_node.inputs['Vector']) + + get_connected_nodes(links, inst, 'Diffuse') + get_connected_nodes(links, inst, 'Specular') - # get or create node group def register_w3d_material_node_group(): @@ -240,14 +328,28 @@ def create_rgb_node(node_tree): return node -def create_uvlayer2(tx_coords, mesh, b_mesh, triangles, name): + + + + + +def get_or_create_uv_layer(mesh, b_mesh, triangles, tx_coords): + for uv_layer in mesh.uv_layers: + layer_exists = True + for i, face in enumerate(b_mesh.faces): + for loop in face.loops: + idx = triangles[i][loop.index % 3] + if uv_layer.data[loop.index].uv != tx_coords[idx].xy: + layer_exists = False + if layer_exists: + return uv_layer + uv_layer = mesh.uv_layers.new(do_init=False) - uv_layer.name = name for i, face in enumerate(b_mesh.faces): for loop in face.loops: idx = triangles[i][loop.index % 3] uv_layer.data[loop.index].uv = tx_coords[idx].xy - return name + return uv_layer ########################################################################## @@ -280,7 +382,7 @@ def create_vertex_material(context, principleds, structure, mesh, name, triangle node_tree = materials[mat_id].node_tree links = node_tree.links - node_tree.nodes.remove(principleds[mat_id]) + #node_tree.nodes.remove(principleds[mat_id]) inst = node_tree.nodes.new(type='ShaderNodeGroup') inst.location = (0, 300) diff --git a/tests/utils.py b/tests/utils.py index b79565e1..6a7504e4 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -8,6 +8,7 @@ import sys import tempfile import unittest +from unittest.mock import patch import addon_utils @@ -65,13 +66,19 @@ def outpath(cls, path=''): def loadBlend(self, blend_file): bpy.ops.wm.open_mainfile(filepath=self.relpath(blend_file)) - def setUp(self): + @patch('threading.Timer.start') + def setUp(self, start): self.filepath = self.outpath() if not os.path.exists(self.__filepath): os.makedirs(self.__filepath) bpy.ops.wm.read_homefile(use_empty=True) addon_utils.enable('io_mesh_w3d', default_set=True) + from io_mesh_w3d.common.utils.material_import import register_alpha_node_group, register_w3d_material_node_group + register_alpha_node_group() + register_w3d_material_node_group() + + def tearDown(self): if os.path.exists(self.__filepath): if self.__save_test_data: From 00d2508e1f031e5092c0c46414c297eab13d9c74 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Thu, 20 Feb 2020 16:03:28 +0100 Subject: [PATCH 22/62] got basic vertex materials working again --- io_mesh_w3d/__init__.py | 3 +- io_mesh_w3d/common/utils/material_import.py | 236 +++++++------------- io_mesh_w3d/common/utils/mesh_import.py | 14 +- 3 files changed, 90 insertions(+), 163 deletions(-) diff --git a/io_mesh_w3d/__init__.py b/io_mesh_w3d/__init__.py index 0ca9f9c3..a7cd2a09 100644 --- a/io_mesh_w3d/__init__.py +++ b/io_mesh_w3d/__init__.py @@ -397,7 +397,8 @@ def draw(self, context): def register_node_groups(): - from io_mesh_w3d.common.utils.material_import import register_w3d_material_node_group + from io_mesh_w3d.common.utils.material_import import register_w3d_material_node_group, register_alpha_node_group + register_alpha_node_group() register_w3d_material_node_group() diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index ad05d240..1b834bc1 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -15,55 +15,6 @@ #node.label -def create_material_passes(base_struct): - for i, mat_pass in enumerate(base_struct.material_passes): - vert_materials = [] - shaders = [] - textures = [] - shader_materials = [] - tx_coords = [] - - for vert_mat_id in mat_pass.vertex_material_ids: - vert_materials.append(base_struct.vert_materials[vert_mat_id]) - - for shader_id in mat_pass.shader_ids: - shaders.append(base_struct.shaders[shader_id]) - - for tx_stage in mat_pass.tx_stages: - textures.append(base_struct.textures[tx_stage.tx_ids[0]]) - tx_coords.append(tx_stage.tx_coords) - - for shader_mat_id in mat_pass.shader_material_ids: - shader_materials.append(base_struct.shader_materials[shader_mat_id]) - - tx_coords.append(mat_pass.tx_coords) - - create_material_pass(ver_materials, shaders, textures, shader_materials, tx_coords, i + 1) - - -def create_material_pass(vert_materials, shaders, textures, shader_materials, tx_coords, index=1): - # TODO: support case where there is only one vertex material and multiple textures? - material = bpy.data.materials.new('meshName.MaterialPass' + str(index)) - - material.material_type = 'VERTEX_MATERIAL' - material.use_nodes = True - material.shadow_method = 'CLIP' - material.blend_method = 'BLEND' - material.show_transparent_back = False - material.pass_index = index - - # get or create node group - node_tree = materials.node_tree - links = node_tree.links - - # delete principled bsdf - principled_bsdf = node_tree.nodes.get('Principled BSDF') - node_tree.nodes.remove(principled_bsdf) - - # create material node (vert_mat, shader) , (shader_mat) - # create texture nodes - - def create_shading_pipeline(vert_material, shader, textures, shader_material, tx_coords, index=1): inst = node_tree.nodes.new(type='ShaderNodeGroup') inst.location = (0, 300) @@ -330,9 +281,6 @@ def create_rgb_node(node_tree): - - - def get_or_create_uv_layer(mesh, b_mesh, triangles, tx_coords): for uv_layer in mesh.uv_layers: layer_exists = True @@ -342,138 +290,84 @@ def get_or_create_uv_layer(mesh, b_mesh, triangles, tx_coords): if uv_layer.data[loop.index].uv != tx_coords[idx].xy: layer_exists = False if layer_exists: - return uv_layer + return uv_layer.name uv_layer = mesh.uv_layers.new(do_init=False) for i, face in enumerate(b_mesh.faces): for loop in face.loops: idx = triangles[i][loop.index % 3] uv_layer.data[loop.index].uv = tx_coords[idx].xy - return uv_layer - + return uv_layer.name -########################################################################## -# vertex material -########################################################################## - -def create_vertex_material(context, principleds, structure, mesh, name, triangles): - for vertMat in structure.vert_materials: - (material, principled) = create_material_from_vertex_material(name, vertMat) - mesh.materials.append(material) - materials.append(material) - principleds.append(principled) - if prelit_type is not None: - material.material_type = 'PRELIT_MATERIAL' - material.prelit_type = prelit_type +def create_material_passes(context, base_struct, mesh, triangles): b_mesh = bmesh.new() b_mesh.from_mesh(mesh) - for mat_pass in structure.material_passes: - create_uvlayer(context, mesh, b_mesh, triangles, mat_pass) - - for mat_pass in struct.material_passes: - if mat_pass.tx_stages: - tx_stage = mat_pass.tx_stages[0] - mat_id = mat_pass.vertex_material_ids[0] - tex_id = tx_stage.tx_ids[0] - - node_tree = materials[mat_id].node_tree - links = node_tree.links - - #node_tree.nodes.remove(principleds[mat_id]) - - inst = node_tree.nodes.new(type='ShaderNodeGroup') - inst.location = (0, 300) - inst.node_tree = bpy.data.node_groups['W3DMaterial'] - inst.inputs['DestBlend'].link_limit = 0 - inst.label = struct.vert_materials[mat_id].vm_name - - output = node_tree.nodes.get('Material Output') - links.new(inst.outputs['BSDF'], output.inputs['Surface']) - - texture_struct = struct.textures[tex_id] - texture = find_texture(context, texture_struct.file, texture_struct.id) - - texture_node = create_texture_node(node_tree, texture) - texture_node.location = (-550, 600) - links.new(texture_node.outputs['Color'], inst.inputs['Diffuse']) - links.new(texture_node.outputs['Alpha'], inst.inputs['Alpha']) - - uv_node = create_uv_map_node(node_tree) - uv_node.uv_map = create_uvlayer2(mat_pass.tx_stages[0].tx_coords, mesh, b_mesh, triangles, 'diffuse') - uv_node.location = (-750, 600) - links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) + for i, mat_pass in enumerate(base_struct.material_passes): + print('material pass') + vert_materials = [] + shaders = [] + textures = [] + shader_materials = [] + tx_coords = [] - texture2_node = create_texture_node(node_tree, None) - texture2_node.location = (-550, 300) - links.new(texture2_node.outputs['Color'], inst.inputs['Diffuse2']) - links.new(texture2_node.outputs['Alpha'], inst.inputs['Alpha2']) + #TODO: create vert_mat - shader - texture combinations + for vert_mat_id in mat_pass.vertex_material_ids: + vert_materials.append(base_struct.vert_materials[vert_mat_id]) - uv2_node = create_uv_map_node(node_tree) - uv2_node.uv_map = create_uvlayer2(mat_pass.tx_stages[0].tx_coords, mesh, b_mesh, triangles, 'diffuse2') - uv2_node.location = (-750, 300) - links.new(uv2_node.outputs['UV'], texture2_node.inputs['Vector']) + for shader_id in mat_pass.shader_ids: + shaders.append(base_struct.shaders[shader_id]) - texture_spec_node = create_texture_node(node_tree, None) - texture_spec_node.location = (-550, 0) - links.new(texture_spec_node.outputs['Color'], inst.inputs['Specular']) + for tx_stage in mat_pass.tx_stages: + textures.append(base_struct.textures[tx_stage.tx_ids[0]]) + tx_coords.append(tx_stage.tx_coords) - uv_spec_node = create_uv_map_node(node_tree) - uv_spec_node.uv_map = create_uvlayer2(mat_pass.tx_stages[0].tx_coords, mesh, b_mesh, triangles, 'specular') - uv_spec_node.location = (-750, 0) - links.new(uv_spec_node.outputs['UV'], texture_spec_node.inputs['Vector']) + for shader_mat_id in mat_pass.shader_material_ids: + shader_materials.append(base_struct.shader_materials[shader_mat_id]) - texture_normal_node = create_texture_node(node_tree, None) - texture_normal_node.location = (-550, -300) - links.new(texture_normal_node.outputs['Color'], inst.inputs['Normal']) - links.new(texture_normal_node.outputs['Alpha'], inst.inputs['Strength']) + if mat_pass.tx_coords: + tx_coords.append(mat_pass.tx_coords) - uv3_node = create_uv_map_node(node_tree) - uv3_node.uv_map = create_uvlayer2(mat_pass.tx_stages[0].tx_coords, mesh, b_mesh, triangles, 'normal') - uv3_node.location = (-750, -300) - links.new(uv3_node.outputs['UV'], texture_normal_node.inputs['Vector']) + print(len(vert_materials)) + if vert_materials: + create_vertex_material(context, mesh, b_mesh, triangles, vert_materials[0], shaders[0], textures[0], tx_coords[0]) - get_connected_nodes(links, inst, 'Diffuse') - get_connected_nodes(links, inst, 'Specular') + #if shader_materials: + # create_shader_material(shader_materials[0], tx_coords[0]) - for i, shader in enumerate(struct.shaders): - set_shader_properties(materials[i], shader) +########################################################################## +# vertex material +########################################################################## -def create_material_from_vertex_material(name, vert_mat): - name = name + "." + vert_mat.vm_name - if name in bpy.data.materials: - material = bpy.data.materials[name] - principled_bsdf = material.node_tree.nodes.get('Principled BSDF') - return material, principled_bsdf +def create_vertex_material(context, mesh, b_mesh, triangles, vert_mat, shader, texture_struct, tx_coords): + print('create material ' + mesh.name) + material = bpy.data.materials.new(mesh.name) + mesh.materials.append(material) - material = bpy.data.materials.new(name) material.material_type = 'VERTEX_MATERIAL' + material.prelit_type = 'PRELIT_UNLIT' material.use_nodes = True material.shadow_method = 'CLIP' material.blend_method = 'BLEND' material.show_transparent_back = False - - attributes = {'DEFAULT'} - attribs = vert_mat.vm_info.attributes - if attribs & USE_DEPTH_CUE: - attributes.add('USE_DEPTH_CUE') - if attribs & ARGB_EMISSIVE_ONLY: - attributes.add('ARGB_EMISSIVE_ONLY') - if attribs & COPY_SPECULAR_TO_DIFFUSE: - attributes.add('COPY_SPECULAR_TO_DIFFUSE') - if attribs & DEPTH_CUE_TO_ALPHA: - attributes.add('DEPTH_CUE_TO_ALPHA') - - material.attributes = atts - - principled_bsdf = material.node_tree.nodes.get('Principled BSDF') - #principled_bsdf.base_color = vert_mat.vm_info.diffuse.to_vector_rgb() - #principled_bsdf.alpha = vert_mat.vm_info.opacity - + #material.pass_index = index + + material.attributes = {'DEFAULT'} + attributes = vert_mat.vm_info.attributes + if attributes & USE_DEPTH_CUE: + material.attributes.add('USE_DEPTH_CUE') + if attributes & ARGB_EMISSIVE_ONLY: + material.attributes.add('ARGB_EMISSIVE_ONLY') + if attributes & COPY_SPECULAR_TO_DIFFUSE: + material.attributes.add('COPY_SPECULAR_TO_DIFFUSE') + if attributes & DEPTH_CUE_TO_ALPHA: + material.attributes.add('DEPTH_CUE_TO_ALPHA') + + # TODO: map these to shader node properties material.specular_intensity = vert_mat.vm_info.shininess material.specular_color = vert_mat.vm_info.specular.to_vector_rgb() material.emission = vert_mat.vm_info.emissive.to_vector_rgba() @@ -484,7 +378,37 @@ def create_material_from_vertex_material(name, vert_mat): material.vm_args_0 = vert_mat.vm_args_0 material.vm_args_1 = vert_mat.vm_args_1 - return material, principled_bsdf + set_shader_properties(material, shader) + + # get or create node group + node_tree = material.node_tree + links = node_tree.links + + # delete principled bsdf + principled_bsdf = node_tree.nodes.get('Principled BSDF') + node_tree.nodes.remove(principled_bsdf) + + inst = node_tree.nodes.new(type='ShaderNodeGroup') + inst.location = (0, 300) + inst.node_tree = bpy.data.node_groups['W3DMaterial'] + inst.label = vert_mat.vm_name + + output = node_tree.nodes.get('Material Output') + links.new(inst.outputs['BSDF'], output.inputs['Surface']) + + texture = find_texture(context, texture_struct.file, texture_struct.id) + + texture_node = create_texture_node(node_tree, texture) + texture_node.location = (-550, 600) + links.new(texture_node.outputs['Color'], inst.inputs['Diffuse']) + links.new(texture_node.outputs['Alpha'], inst.inputs['Alpha']) + + uv_layer = get_or_create_uv_layer(mesh, b_mesh, triangles, tx_coords) + + uv_node = create_uv_map_node(node_tree) + uv_node.uv_map = uv_layer + uv_node.location = (-750, 600) + links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) ########################################################################## diff --git a/io_mesh_w3d/common/utils/mesh_import.py b/io_mesh_w3d/common/utils/mesh_import.py index 80ef4670..3545a877 100644 --- a/io_mesh_w3d/common/utils/mesh_import.py +++ b/io_mesh_w3d/common/utils/mesh_import.py @@ -30,13 +30,15 @@ def create_mesh(context, mesh_struct, coll): if mesh_struct.is_hidden(): mesh_ob.hide_set(True) - create_shader_materials(context, mesh_struct, mesh, triangles) + create_material_passes(context, mesh_struct, mesh, triangles) - create_vertex_materials(context, mesh_struct, mesh, triangles) - create_vertex_materials(context, mesh_struct.prelit_unlit, mesh, triangles, prelit_type='PRELIT_UNLIT') - create_vertex_materials(context, mesh_struct.prelit_vertex, mesh, triangles, prelit_type='PRELIT_VERTEX') - create_vertex_materials(context, mesh_struct.prelit_lightmap_multi_pass, mesh, triangles, prelit_type='PRELIT_LIGHTMAP_MULTI_PASS') - create_vertex_materials(context, mesh_struct.prelit_lightmap_multi_texture, mesh, triangles, prelit_type='PRELIT_LIGHTMAP_MULTI_TEXTURE') + # create_shader_materials(context, mesh_struct, mesh, triangles) + + #create_vertex_materials(context, mesh_struct, mesh, triangles) + #create_vertex_materials(context, mesh_struct.prelit_unlit, mesh, triangles, prelit_type='PRELIT_UNLIT') + #create_vertex_materials(context, mesh_struct.prelit_vertex, mesh, triangles, prelit_type='PRELIT_VERTEX') + #create_vertex_materials(context, mesh_struct.prelit_lightmap_multi_pass, mesh, triangles, prelit_type='PRELIT_LIGHTMAP_MULTI_PASS') + #create_vertex_materials(context, mesh_struct.prelit_lightmap_multi_texture, mesh, triangles, prelit_type='PRELIT_LIGHTMAP_MULTI_TEXTURE') def rig_mesh(mesh_struct, hierarchy, rig, sub_object=None): From 2685ed5a7400dcbf4199bdec87cd257af7ebc8f1 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Thu, 20 Feb 2020 16:36:43 +0100 Subject: [PATCH 23/62] got basic shader materials working again --- io_mesh_w3d/common/utils/material_import.py | 166 ++++++++------------ 1 file changed, 66 insertions(+), 100 deletions(-) diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index 1b834bc1..b1e1feb6 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -14,63 +14,6 @@ #node.name = 'Test' #node.label - -def create_shading_pipeline(vert_material, shader, textures, shader_material, tx_coords, index=1): - inst = node_tree.nodes.new(type='ShaderNodeGroup') - inst.location = (0, 300) - inst.node_tree = bpy.data.node_groups['W3DMaterial'] - inst.label = struct.vert_materials[mat_id].vm_name - - output = node_tree.nodes.get('Material Output') - links.new(inst.outputs['BSDF'], output.inputs['Surface']) - - texture_struct = struct.textures[tex_id] - texture = find_texture(context, texture_struct.file, texture_struct.id) - - texture_node = create_texture_node(node_tree, texture) - texture_node.location = (-550, 600) - links.new(texture_node.outputs['Color'], inst.inputs['Diffuse']) - links.new(texture_node.outputs['Alpha'], inst.inputs['Alpha']) - - uv_node = create_uv_map_node(node_tree) - uv_node.uv_map = create_uvlayer2(mat_pass.tx_stages[0].tx_coords, mesh, b_mesh, triangles, 'diffuse') - uv_node.location = (-750, 600) - links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) - - texture2_node = create_texture_node(node_tree, None) - texture2_node.location = (-550, 300) - links.new(texture2_node.outputs['Color'], inst.inputs['Diffuse2']) - links.new(texture2_node.outputs['Alpha'], inst.inputs['Alpha2']) - - uv2_node = create_uv_map_node(node_tree) - uv2_node.uv_map = create_uvlayer2(mat_pass.tx_stages[0].tx_coords, mesh, b_mesh, triangles, 'diffuse2') - uv2_node.location = (-750, 300) - links.new(uv2_node.outputs['UV'], texture2_node.inputs['Vector']) - - texture_spec_node = create_texture_node(node_tree, None) - texture_spec_node.location = (-550, 0) - links.new(texture_spec_node.outputs['Color'], inst.inputs['Specular']) - - uv_spec_node = create_uv_map_node(node_tree) - uv_spec_node.uv_map = create_uvlayer2(mat_pass.tx_stages[0].tx_coords, mesh, b_mesh, triangles, 'specular') - uv_spec_node.location = (-750, 0) - links.new(uv_spec_node.outputs['UV'], texture_spec_node.inputs['Vector']) - - texture_normal_node = create_texture_node(node_tree, None) - texture_normal_node.location = (-550, -300) - links.new(texture_normal_node.outputs['Color'], inst.inputs['Normal']) - links.new(texture_normal_node.outputs['Alpha'], inst.inputs['Strength']) - - uv3_node = create_uv_map_node(node_tree) - uv3_node.uv_map = create_uvlayer2(mat_pass.tx_stages[0].tx_coords, mesh, b_mesh, triangles, 'normal') - uv3_node.location = (-750, -300) - links.new(uv3_node.outputs['UV'], texture_normal_node.inputs['Vector']) - - get_connected_nodes(links, inst, 'Diffuse') - get_connected_nodes(links, inst, 'Specular') - - - def register_w3d_material_node_group(): group = bpy.data.node_groups.new('W3DMaterial', 'ShaderNodeTree') node_tree = group @@ -306,7 +249,6 @@ def create_material_passes(context, base_struct, mesh, triangles): b_mesh.from_mesh(mesh) for i, mat_pass in enumerate(base_struct.material_passes): - print('material pass') vert_materials = [] shaders = [] textures = [] @@ -330,12 +272,11 @@ def create_material_passes(context, base_struct, mesh, triangles): if mat_pass.tx_coords: tx_coords.append(mat_pass.tx_coords) - print(len(vert_materials)) if vert_materials: create_vertex_material(context, mesh, b_mesh, triangles, vert_materials[0], shaders[0], textures[0], tx_coords[0]) - #if shader_materials: - # create_shader_material(shader_materials[0], tx_coords[0]) + if shader_materials: + create_shader_material(context, mesh, b_mesh, triangles, shader_materials[0], tx_coords[0]) @@ -368,9 +309,6 @@ def create_vertex_material(context, mesh, b_mesh, triangles, vert_mat, shader, t material.attributes.add('DEPTH_CUE_TO_ALPHA') # TODO: map these to shader node properties - material.specular_intensity = vert_mat.vm_info.shininess - material.specular_color = vert_mat.vm_info.specular.to_vector_rgb() - material.emission = vert_mat.vm_info.emissive.to_vector_rgba() material.ambient = vert_mat.vm_info.ambient.to_vector_rgba() material.translucency = vert_mat.vm_info.translucency material.opacity = vert_mat.vm_info.opacity @@ -393,13 +331,17 @@ def create_vertex_material(context, mesh, b_mesh, triangles, vert_mat, shader, t inst.node_tree = bpy.data.node_groups['W3DMaterial'] inst.label = vert_mat.vm_name + inst.inputs['Specular'].default_value = vert_mat.vm_info.specular.to_vector_rgba() + inst.inputs['Roughness'].default_value = vert_mat.vm_info.shininess + inst.inputs['Emissive'].default_value = vert_mat.vm_info.emissive.to_vector_rgba() + output = node_tree.nodes.get('Material Output') links.new(inst.outputs['BSDF'], output.inputs['Surface']) texture = find_texture(context, texture_struct.file, texture_struct.id) texture_node = create_texture_node(node_tree, texture) - texture_node.location = (-550, 600) + texture_node.location = (-250, 0) links.new(texture_node.outputs['Color'], inst.inputs['Diffuse']) links.new(texture_node.outputs['Alpha'], inst.inputs['Alpha']) @@ -407,7 +349,7 @@ def create_vertex_material(context, mesh, b_mesh, triangles, vert_mat, shader, t uv_node = create_uv_map_node(node_tree) uv_node.uv_map = uv_layer - uv_node.location = (-750, 600) + uv_node.location = (-450, 0) links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) @@ -415,28 +357,10 @@ def create_vertex_material(context, mesh, b_mesh, triangles, vert_mat, shader, t # shader material ########################################################################## -def create_shader_materials(context, struct, mesh, triangles): - for i, shaderMat in enumerate(struct.shader_materials): - (material, principled) = create_material_from_shader_material( - context, mesh.name, shaderMat) - mesh.materials.append(material) - - if struct.material_passes: - b_mesh = bmesh.new() - b_mesh.from_mesh(mesh) - - for mat_pass in struct.material_passes: - create_uvlayer(context, mesh, b_mesh, triangles, mat_pass) - -def create_material_from_shader_material(context, name, shader_mat): - name = name + '.' + shader_mat.header.type_name - if name in bpy.data.materials: - material = bpy.data.materials[name] - principled = node_shader_utils.PrincipledBSDFWrapper(material, is_readonly=False) - return material, principled - - material = bpy.data.materials.new(name) +def create_shader_material(context, mesh, b_mesh, triangles, shader_mat, tx_coords): + material = bpy.data.materials.new(mesh.name) + mesh.materials.append(material) material.material_type = 'SHADER_MATERIAL' material.use_nodes = True material.blend_method = 'BLEND' @@ -445,27 +369,73 @@ def create_material_from_shader_material(context, name, shader_mat): if shader_mat.header.technique is not None: material.technique = shader_mat.header.technique - principled = node_shader_utils.PrincipledBSDFWrapper(material, is_readonly=False) + # get or create node group + node_tree = material.node_tree + links = node_tree.links + + # delete principled bsdf + principled_bsdf = node_tree.nodes.get('Principled BSDF') + node_tree.nodes.remove(principled_bsdf) + + inst = node_tree.nodes.new(type='ShaderNodeGroup') + inst.location = (0, 300) + inst.node_tree = bpy.data.node_groups['W3DMaterial'] + inst.label = shader_mat.header.type_name + + output = node_tree.nodes.get('Material Output') + links.new(inst.outputs['BSDF'], output.inputs['Surface']) + + uv_layer = get_or_create_uv_layer(mesh, b_mesh, triangles, tx_coords) for prop in shader_mat.properties: - if prop.name == 'DiffuseTexture' and prop.value != '': - principled.base_color_texture.image = find_texture(context, prop.value) + if prop.name in ['DiffuseTexture', 'Texture_0'] and prop.value != '': + texture_node = create_texture_node(node_tree, find_texture(context, prop.value)) + texture_node.location = (-550, 600) + links.new(texture_node.outputs['Color'], inst.inputs['Diffuse']) + links.new(texture_node.outputs['Alpha'], inst.inputs['Alpha']) + + uv_node = create_uv_map_node(node_tree) + uv_node.uv_map = uv_layer + uv_node.location = (-750, 600) + links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) elif prop.name == 'NormalMap' and prop.value != '': - principled.normalmap_texture.image = find_texture(context, prop.value) + texture_node = create_texture_node(node_tree, find_texture(context, prop.value)) + texture_node.location = (-550, -300) + links.new(texture_node.outputs['Color'], inst.inputs['Normal']) + + uv_node = create_uv_map_node(node_tree) + uv_node.uv_map = uv_layer + uv_node.location = (-750, -300) + links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) elif prop.name == 'BumpScale': - principled.normalmap_strength = prop.value + inst.inputs['Strength'].default_value = prop.value elif prop.name == 'SpecMap' and prop.value != '': - principled.specular_texture.image = find_texture(context, prop.value) + texture_node = create_texture_node(node_tree, find_texture(context, prop.value)) + texture_node.location = (-550, 0) + links.new(texture_node.outputs['Color'], inst.inputs['Specular']) + + uv_node = create_uv_map_node(node_tree) + uv_node.uv_map = uv_layer + uv_node.location = (-750, 0) + links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) elif prop.name == 'SpecularExponent' or prop.name == 'Shininess': - material.specular_intensity = prop.value / 200.0 + inst.inputs['Roughness'].default_value = prop.value / 200.0 elif prop.name == 'DiffuseColor' or prop.name == 'ColorDiffuse': material.diffuse_color = prop.to_rgba() elif prop.name == 'SpecularColor' or prop.name == 'ColorSpecular': material.specular_color = prop.to_rgb() elif prop.name == 'CullingEnable': material.use_backface_culling = prop.value - elif prop.name == 'Texture_0': - principled.base_color_texture.image = find_texture(context, prop.value) + elif prop.name == 'Texture_1': + texture_node = create_texture_node(node_tree, find_texture(context, prop.value)) + texture_node.location = (-550, 300) + links.new(texture_node.outputs['Color'], inst.inputs['Diffuse2']) + links.new(texture_node.outputs['Alpha'], inst.inputs['Alpha2']) + + uv_node = create_uv_map_node(node_tree) + uv_node.uv_map = uv_layer + uv_node.location = (-750, 300) + links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) # all props below have no effect on shading -> custom properties for roundtrip purpose elif prop.name == 'AmbientColor' or prop.name == 'ColorAmbient': @@ -490,8 +460,6 @@ def create_material_from_shader_material(context, name, shader_mat): material.sampler_clamp_uv_no_mip_1 = prop.value elif prop.name == 'NumTextures': material.num_textures = prop.value # is 1 if texture_0 and texture_1 are set - elif prop.name == 'Texture_1': # second diffuse texture - material.texture_1 = prop.value elif prop.name == 'SecondaryTextureBlendMode': material.secondary_texture_blend_mode = prop.value elif prop.name == 'TexCoordMapper_0': @@ -539,8 +507,6 @@ def create_material_from_shader_material(context, name, shader_mat): else: context.error('shader property not implemented: ' + prop.name) - return material, principled - ########################################################################## # set shader properties From 10e3d0a292d3faf86d7bd0787c6885bb6e860e72 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Thu, 20 Feb 2020 17:19:13 +0100 Subject: [PATCH 24/62] small changes --- io_mesh_w3d/common/utils/material_import.py | 37 +++++++++++++-------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index b1e1feb6..dc4c9b2c 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -8,7 +8,6 @@ from io_mesh_w3d.common.utils.helpers import * from io_mesh_w3d.w3d.structs.mesh_structs.vertex_material import * - #node.color = (1, 0, 0) #node.use_custom_color = True #node.name = 'Test' @@ -272,8 +271,20 @@ def create_material_passes(context, base_struct, mesh, triangles): if mat_pass.tx_coords: tx_coords.append(mat_pass.tx_coords) + print('vert: ' + str(len(vert_materials))) + print('shaders: ' + str(len(shaders))) + print('textures: ' + str(len(textures))) + print('shader_materials: ' + str(len(shader_materials))) + print('tx_coords: ' + str(len(tx_coords))) + if vert_materials: - create_vertex_material(context, mesh, b_mesh, triangles, vert_materials[0], shaders[0], textures[0], tx_coords[0]) + texture = None + if textures: + texture = textures[0] + tx_coordinates = None + if tx_coords: + tx_coordinates = tx_coords[0] + create_vertex_material(context, mesh, b_mesh, triangles, vert_materials[0], shaders[0], texture, tx_coordinates) if shader_materials: create_shader_material(context, mesh, b_mesh, triangles, shader_materials[0], tx_coords[0]) @@ -285,7 +296,6 @@ def create_material_passes(context, base_struct, mesh, triangles): ########################################################################## def create_vertex_material(context, mesh, b_mesh, triangles, vert_mat, shader, texture_struct, tx_coords): - print('create material ' + mesh.name) material = bpy.data.materials.new(mesh.name) mesh.materials.append(material) @@ -338,19 +348,20 @@ def create_vertex_material(context, mesh, b_mesh, triangles, vert_mat, shader, t output = node_tree.nodes.get('Material Output') links.new(inst.outputs['BSDF'], output.inputs['Surface']) - texture = find_texture(context, texture_struct.file, texture_struct.id) + if texture_struct is not None: + texture = find_texture(context, texture_struct.file, texture_struct.id) - texture_node = create_texture_node(node_tree, texture) - texture_node.location = (-250, 0) - links.new(texture_node.outputs['Color'], inst.inputs['Diffuse']) - links.new(texture_node.outputs['Alpha'], inst.inputs['Alpha']) + texture_node = create_texture_node(node_tree, texture) + texture_node.location = (-250, 0) + links.new(texture_node.outputs['Color'], inst.inputs['Diffuse']) + links.new(texture_node.outputs['Alpha'], inst.inputs['Alpha']) - uv_layer = get_or_create_uv_layer(mesh, b_mesh, triangles, tx_coords) + uv_layer = get_or_create_uv_layer(mesh, b_mesh, triangles, tx_coords) - uv_node = create_uv_map_node(node_tree) - uv_node.uv_map = uv_layer - uv_node.location = (-450, 0) - links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) + uv_node = create_uv_map_node(node_tree) + uv_node.uv_map = uv_layer + uv_node.location = (-450, 0) + links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) ########################################################################## From 08ca04ab7c653d0f24de0fb8d512f55ec601dd09 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Fri, 3 Apr 2020 20:40:11 +0200 Subject: [PATCH 25/62] got vertex material and normalMapped shader material import working again --- io_mesh_w3d/__init__.py | 150 ++----- .../common/node_groups/alpha_pipeline.py | 60 +++ io_mesh_w3d/common/node_groups/helpers.py | 109 +++++ .../common/node_groups/normal_mapped.py | 113 +++++ .../common/node_groups/vertex_material.py | 120 +++++ io_mesh_w3d/common/utils/NodeShaderWrapper.py | 66 --- io_mesh_w3d/common/utils/material_import.py | 423 +----------------- io_mesh_w3d/custom_properties.py | 274 +----------- 8 files changed, 452 insertions(+), 863 deletions(-) create mode 100644 io_mesh_w3d/common/node_groups/alpha_pipeline.py create mode 100644 io_mesh_w3d/common/node_groups/helpers.py create mode 100644 io_mesh_w3d/common/node_groups/normal_mapped.py create mode 100644 io_mesh_w3d/common/node_groups/vertex_material.py delete mode 100644 io_mesh_w3d/common/utils/NodeShaderWrapper.py diff --git a/io_mesh_w3d/__init__.py b/io_mesh_w3d/__init__.py index a7cd2a09..a960450a 100644 --- a/io_mesh_w3d/__init__.py +++ b/io_mesh_w3d/__init__.py @@ -263,133 +263,27 @@ class MATERIAL_PROPERTIES_PANEL_PT_w3d(Panel): def draw(self, context): layout = self.layout mat = context.object.active_material - col = layout.column() - col.prop(mat, 'material_type') - - if mat.material_type == 'PRELIT_MATERIAL': - col = layout.column() - col.prop(mat, 'prelit_type') - - col = layout.column() - col.prop(mat, 'surface_type') - col = layout.column() - col.prop(mat, 'blend_mode') - col = layout.column() - col.prop(mat, 'ambient') - col = layout.column() - col.prop(mat, 'opacity') - if mat.material_type == 'VERTEX_MATERIAL' or mat.material_type == 'PRELIT_MATERIAL': - col = layout.column() - col.prop(mat, 'attributes') - col = layout.column() - col.prop(mat, 'translucency') - col = layout.column() - col.prop(mat, 'vm_args_0') - col = layout.column() - col.prop(mat, 'vm_args_1') + for node in mat.node_tree.nodes: + + if not hasattr(node, 'node_tree'): + continue + print(node.node_tree.name) + if node.node_tree.name in ['VertexMaterial', 'PrelitUnlit', 'PrelitVertex', 'PrelitLightmapMultiPass', 'PrelitLightmapMultiTextue']: + col = layout.column() + col.prop(mat, 'surface_type') + col = layout.column() + col.prop(mat, 'attributes') + col = layout.column() + col.prop(mat, 'vm_args_0') + col = layout.column() + col.prop(mat, 'vm_args_1') - col = layout.column() - layout.label(text="Shader Properties") - col = layout.column() - col.prop(mat.shader, 'depth_compare') - col = layout.column() - col.prop(mat.shader, 'depth_mask') - col = layout.column() - col.prop(mat.shader, 'color_mask') - col = layout.column() - col.prop(mat.shader, 'dest_blend') - col = layout.column() - col.prop(mat.shader, 'fog_func') - col = layout.column() - col.prop(mat.shader, 'pri_gradient') - col = layout.column() - col.prop(mat.shader, 'sec_gradient') - col = layout.column() - col.prop(mat.shader, 'src_blend') - col = layout.column() - col.prop(mat.shader, 'texturing') - col = layout.column() - col.prop(mat.shader, 'detail_color_func') - col = layout.column() - col.prop(mat.shader, 'detail_alpha_func') - col = layout.column() - col.prop(mat.shader, 'shader_preset') - col = layout.column() - col.prop(mat.shader, 'alpha_test') - col = layout.column() - col.prop(mat.shader,'post_detail_color_func') - col = layout.column() - col.prop(mat.shader,'post_detail_alpha_func') - - else: - col = layout.column() - col.prop(mat, 'technique') - col.prop(mat, 'alpha_test') - col = layout.column() - col.prop(mat, 'bump_uv_scale') - col = layout.column() - col.prop(mat, 'edge_fade_out') - col = layout.column() - col.prop(mat, 'depth_write') - col = layout.column() - col.prop(mat, 'sampler_clamp_uv_no_mip_0') - col = layout.column() - col.prop(mat, 'sampler_clamp_uv_no_mip_1') - col = layout.column() - col.prop(mat, 'num_textures') - col = layout.column() - col.prop(mat, 'texture_1') - col = layout.column() - col.prop(mat, 'secondary_texture_blend_mode') - col = layout.column() - col.prop(mat, 'tex_coord_mapper_0') - col = layout.column() - col.prop(mat, 'tex_coord_mapper_1') - col = layout.column() - col.prop(mat, 'tex_coord_transform_0') - col = layout.column() - col.prop(mat, 'tex_coord_transform_1') - col = layout.column() - col.prop(mat, 'environment_texture') - col = layout.column() - col.prop(mat, 'environment_mult') - col = layout.column() - col.prop(mat, 'recolor_texture') - col = layout.column() - col.prop(mat, 'recolor_mult') - col = layout.column() - col.prop(mat, 'use_recolor') - col = layout.column() - col.prop(mat, 'house_color_pulse') - col = layout.column() - col.prop(mat, 'scrolling_mask_texture') - col = layout.column() - col.prop(mat, 'tex_coord_transform_angle') - col = layout.column() - col.prop(mat, 'tex_coord_transform_u_0') - col = layout.column() - col.prop(mat, 'tex_coord_transform_v_0') - col = layout.column() - col.prop(mat, 'tex_coord_transform_u_1') - col = layout.column() - col.prop(mat, 'tex_coord_transform_v_1') - col = layout.column() - col.prop(mat, 'tex_coord_transform_u_2') - col = layout.column() - col.prop(mat, 'tex_coord_transform_v_2') - col = layout.column() - col.prop(mat, 'tex_ani_fps_NPR_lastFrame_frameOffset_0') - col = layout.column() - col.prop(mat, 'ion_hull_texture') - col = layout.column() - col.prop(mat, 'multi_texture_enable') CLASSES = ( ExportW3D, ImportW3D, - ShaderProperties, OBJECT_PROPERTIES_PANEL_PT_w3d, BONE_PROPERTIES_PANEL_PT_w3d, MATERIAL_PROPERTIES_PANEL_PT_w3d @@ -397,17 +291,23 @@ def draw(self, context): def register_node_groups(): - from io_mesh_w3d.common.utils.material_import import register_w3d_material_node_group, register_alpha_node_group - register_alpha_node_group() - register_w3d_material_node_group() + from io_mesh_w3d.common.node_groups.alpha_pipeline import AlphaPipeline + AlphaPipeline.register() + + from io_mesh_w3d.common.node_groups.vertex_material import VertexMaterialGroup, PrelitUnlitGroup, PrelitVertexGroup, PrelitLightmapMultiPassGroup, PrelitLightmapMultiTextureGroup + VertexMaterialGroup.register(VertexMaterialGroup.name) + PrelitUnlitGroup.register(PrelitUnlitGroup.name) + PrelitVertexGroup.register(PrelitVertexGroup.name) + PrelitLightmapMultiPassGroup.register(PrelitLightmapMultiPassGroup.name) + PrelitLightmapMultiTextureGroup.register(PrelitLightmapMultiTextureGroup.name) + from io_mesh_w3d.common.node_groups.normal_mapped import NormalMappedGroup + NormalMappedGroup.register() def register(): for class_ in CLASSES: bpy.utils.register_class(class_) - Material.shader = PointerProperty(type=ShaderProperties) - bpy.types.TOPBAR_MT_file_import.append(menu_func_import) bpy.types.TOPBAR_MT_file_export.append(menu_func_export) diff --git a/io_mesh_w3d/common/node_groups/alpha_pipeline.py b/io_mesh_w3d/common/node_groups/alpha_pipeline.py new file mode 100644 index 00000000..8da8b486 --- /dev/null +++ b/io_mesh_w3d/common/node_groups/alpha_pipeline.py @@ -0,0 +1,60 @@ +# +# Written by Stephan Vedder and Michael Schnabel + +import bpy +from io_mesh_w3d.common.node_groups.helpers import * + +class AlphaPipeline(): + name = 'AlphaPipeline' + + @staticmethod + def register(): + group = bpy.data.node_groups.new(AlphaPipeline.name, 'ShaderNodeTree') + node_tree = group + links = node_tree.links + + # create group inputs + group_inputs = group.nodes.new('NodeGroupInput') + group_inputs.location = (-500,0) + group.inputs.new('NodeSocketColor', 'Diffuse') + group.inputs.new('NodeSocketFloat', 'Alpha') + group.inputs['Alpha'].default_value = 1.0 + group.inputs.new('NodeSocketInt', 'DestBlend') + group.inputs['DestBlend'].default_value = 0 + group.inputs['DestBlend'].min_value = 0 + group.inputs['DestBlend'].max_value = 1 + + # create group outputs + group_outputs = group.nodes.new('NodeGroupOutput') + group_outputs.location = (500,0) + group.outputs.new('NodeSocketFloat', 'Alpha') + + # default texture alpha + compare_1 = create_math_node(node_tree, mode='COMPARE') + compare_1.location = (-200, 100) + compare_1.inputs[0].default_value = 0 + links.new(group_inputs.outputs['DestBlend'], compare_1.inputs[1]) + links.new(group_inputs.outputs['Alpha'], compare_1.inputs[2]) + + # v of diffuse + seperate_hsv = create_seperate_hsv_node(node_tree) + seperate_hsv.location = (-300, -100) + links.new(group_inputs.outputs['Diffuse'], seperate_hsv.inputs['Color']) + + compare_2 = create_math_node(node_tree, mode='COMPARE') + compare_2.location = (-100, -100) + compare_2.inputs[0].default_value = 1 + links.new(group_inputs.outputs['DestBlend'], compare_2.inputs[1]) + links.new(seperate_hsv.outputs['V'], compare_2.inputs[2]) + + # both + add_node = create_math_node(node_tree, mode='ADD') + add_node.location = (100, 0) + links.new(compare_1.outputs['Value'], add_node.inputs[0]) + links.new(compare_2.outputs['Value'], add_node.inputs[1]) + + subtract_node = create_math_node(node_tree, mode='SUBTRACT') + subtract_node.location = (300, 0) + subtract_node.inputs[0].default_value = 1.0 + links.new(add_node.outputs['Value'], subtract_node.inputs[1]) + links.new(subtract_node.outputs['Value'], group_outputs.inputs['Alpha']) \ No newline at end of file diff --git a/io_mesh_w3d/common/node_groups/helpers.py b/io_mesh_w3d/common/node_groups/helpers.py new file mode 100644 index 00000000..b0cea983 --- /dev/null +++ b/io_mesh_w3d/common/node_groups/helpers.py @@ -0,0 +1,109 @@ +# +# Written by Stephan Vedder and Michael Schnabel + + + #node.color = (1, 0.5, 0) + #node.use_custom_color = True + #node.name = 'Test' + #node.label + +def addInputInt(group, name, default=0, min=0, max=255): + group.inputs.new('NodeSocketInt', name) + group.inputs[name].default_value = default + group.inputs[name].min_value = min + group.inputs[name].max_value = max + + +def create_specular_shader_node(node_tree): + # inputs: Base Color, Specular, Roughness, Emissive Color, Transparency, + # Normal, Clear Coat, Clear Coat Radius, Clear Coat Normal, Ambient Occlusion + # outputs: BSDF + + node = node_tree.nodes.new('ShaderNodeEeveeSpecular') + node.label = 'Shader' + # hide unused inputs + node.inputs['Clear Coat'].hide = True + node.inputs['Clear Coat Roughness'].hide = True + node.inputs['Clear Coat Normal'].hide = True + node.inputs['Ambient Occlusion'].hide = True + return node + +def create_texture_node(node_tree, texture): + # inputs: Vector + # outputs: Color, Alpha + + node = node_tree.nodes.new('ShaderNodeTexImage') + #node.color_mapping + #node.extension # interpolation past bounds + node.image = texture + #node.image_user + #node.interpolation + #node.projection + #node.projection_blend + #node.texture_mapping + return node + +def create_uv_map_node(node_tree): + # outputs: UV + + node = node_tree.nodes.new('ShaderNodeUVMap') + #node.uv_map = 'uvmapname' + return node + +def create_math_node(node_tree, mode='SUBTRACT'): + # inputs: Value, Value + # outputs: Value + + node = node_tree.nodes.new('ShaderNodeMath') + node.operation = mode + #node.clamp = False + return node + +def create_rgb_mix_node(node_tree): + # inputs: Fac, Color1, Color2 + # outputs: Color + + node = node_tree.nodes.new('ShaderNodeMixRGB') + #node.blend_type + #node.use_alpha + #node.use_clamp + return node + +def create_normal_map_node(node_tree): + # inputs: Strength, Color + # outputs: Normal + + node = node_tree.nodes.new('ShaderNodeNormalMap') + node.space = 'TANGENT' + #node.uv_map = 'uvmapname' + return node + +def create_seperate_hsv_node(node_tree): + # inputs: Color + # outputs: H, S, V + + node = node_tree.nodes.new('ShaderNodeSeparateHSV') + return node + +def create_rgb_node(node_tree): + # outputs: Color + + node = node_tree.nodes.new('ShaderNodeRGB') + return node + +def get_connected_nodes(links, node, input, types=[]): + nodes = [] + for link in links: + #print(link.to_node) + #print(link.to_socket) + if link.to_node == node and link.to_socket.identifier == input: + # and link.from_socket in outputs: + # and type(node) == bpy.types.ShaderNodeTexture.... + # and node.inputs[''].is_linked + nodes.append(link.from_node) + + for node in nodes: + print('###') + print(node.bl_idname) + print(node.name) + return nodes \ No newline at end of file diff --git a/io_mesh_w3d/common/node_groups/normal_mapped.py b/io_mesh_w3d/common/node_groups/normal_mapped.py new file mode 100644 index 00000000..6a150212 --- /dev/null +++ b/io_mesh_w3d/common/node_groups/normal_mapped.py @@ -0,0 +1,113 @@ +# +# Written by Stephan Vedder and Michael Schnabel + +import bpy +from io_mesh_w3d.common.utils.helpers import * +from io_mesh_w3d.common.node_groups.helpers import * + + +class NormalMappedGroup(): + + @staticmethod + def create(context, node_tree, shader_mat, uv_layer): + instance = node_tree.nodes.new(type='ShaderNodeGroup') + instance.node_tree = bpy.data.node_groups['NormalMapped'] + instance.label = 'NormalMapped.fx' + instance.location = (0, 300) + instance.width = 300 + + links = node_tree.links + + if shader_mat.header.technique is not None: + instance.inputs['Technique'].default_value = shader_mat.header.technique + + for prop in shader_mat.properties: + if prop.name in ['DiffuseTexture', 'Texture_0'] and prop.value != '': + texture_node = create_texture_node(node_tree, find_texture(context, prop.value)) + texture_node.location = (-550, 600) + links.new(texture_node.outputs['Color'], instance.inputs['DiffuseTexture']) + links.new(texture_node.outputs['Alpha'], instance.inputs['DiffuseTextureAlpha']) + uv_node = create_uv_map_node(node_tree) + uv_node.uv_map = uv_layer + uv_node.location = (-750, 600) + links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) + + elif prop.name == 'NormalMap' and prop.value != '': + texture_node = create_texture_node(node_tree, find_texture(context, prop.value)) + texture_node.location = (-550, -300) + links.new(texture_node.outputs['Color'], instance.inputs['NormalMap']) + links.new(texture_node.outputs['Alpha'], instance.inputs['NormalMapStrength']) + uv_node = create_uv_map_node(node_tree) + uv_node.uv_map = uv_layer + uv_node.location = (-750, -300) + links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) + + elif prop.name in ['DiffuseColor', 'ColorDiffuse']: + instance.inputs['Diffuse'].default_value = prop.to_rgba() + elif prop.name in ['AmbientColor', 'ColorAmbient']: + instance.inputs['Ambient'].default_value = prop.to_rgba() + elif prop.name in ['SpecularColor', 'ColorSpecular']: + instance.inputs['Specular'].default_value = prop.to_rgba() + elif prop.name in ['SpecularExponent', 'BumpScale', 'AlphaTestEnable']: + instance.inputs[prop.name].default_value = prop.value + else: + print(prop.name + ' -> is not a valid input of NormalMapped.fx') + + return instance + + @staticmethod + def register(): + name = 'NormalMapped' + group = bpy.data.node_groups.new(name, 'ShaderNodeTree') + node_tree = group + node_tree.name = name + links = node_tree.links + + # create group inputs + group_inputs = group.nodes.new('NodeGroupInput') + group_inputs.location = (-350,0) + + addInputInt(group, 'Technique', default=1, min=0, max=3) + group.inputs.new('NodeSocketColor', 'Diffuse') + group.inputs['Diffuse'].default_value = (0.8, 0.8, 0.8, 1.0) + group.inputs.new('NodeSocketColor', 'DiffuseTexture') + group.inputs['DiffuseTexture'].default_value = (0.8, 0.8, 0.8, 1.0) + group.inputs.new('NodeSocketFloat', 'DiffuseTextureAlpha') + group.inputs['DiffuseTextureAlpha'].default_value = 1.0 + addInputInt(group, 'AlphaTestEnable', max=1) + group.inputs.new('NodeSocketColor', 'NormalMap') + group.inputs.new('NodeSocketFloat', 'NormalMapStrength') + group.inputs.new('NodeSocketFloat', 'BumpScale') + group.inputs.new('NodeSocketColor', 'Ambient') + group.inputs['Ambient'].default_value = (0.8, 0.8, 0.8, 1.0) + group.inputs.new('NodeSocketColor', 'Specular') + group.inputs['Specular'].default_value = (0.8, 0.8, 0.8, 1.0) + group.inputs.new('NodeSocketFloat', 'SpecularExponent') + + # create group outputs + group_outputs = group.nodes.new('NodeGroupOutput') + group_outputs.location = (300,0) + group.outputs.new('NodeSocketShader', 'BSDF') + + alpha_pipeline = node_tree.nodes.new(type='ShaderNodeGroup') + alpha_pipeline.location = (-100, 0) + alpha_pipeline.node_tree = bpy.data.node_groups['AlphaPipeline'] + links.new(group_inputs.outputs['DiffuseTexture'], alpha_pipeline.inputs['Diffuse']) + links.new(group_inputs.outputs['DiffuseTextureAlpha'], alpha_pipeline.inputs['Alpha']) + links.new(group_inputs.outputs['AlphaTestEnable'], alpha_pipeline.inputs['DestBlend']) + + normal = create_normal_map_node(node_tree) + normal.location = (-100, -200) + links.new(group_inputs.outputs['NormalMap'], normal.inputs['Color']) + links.new(group_inputs.outputs['NormalMapStrength'], normal.inputs['Strength']) + + shader = create_specular_shader_node(node_tree) + shader.location = (100, 0) + shader.inputs['Emissive Color'].hide = True + + links.new(group_inputs.outputs['DiffuseTexture'], shader.inputs['Base Color']) + links.new(group_inputs.outputs['Specular'], shader.inputs['Specular']) + links.new(group_inputs.outputs['SpecularExponent'], shader.inputs['Roughness']) + links.new(alpha_pipeline.outputs['Alpha'], shader.inputs['Transparency']) + links.new(normal.outputs['Normal'], shader.inputs['Normal']) + links.new(shader.outputs['BSDF'], group_outputs.inputs['BSDF']) diff --git a/io_mesh_w3d/common/node_groups/vertex_material.py b/io_mesh_w3d/common/node_groups/vertex_material.py new file mode 100644 index 00000000..e15287ec --- /dev/null +++ b/io_mesh_w3d/common/node_groups/vertex_material.py @@ -0,0 +1,120 @@ +# +# Written by Stephan Vedder and Michael Schnabel + +import bpy +from io_mesh_w3d.common.node_groups.helpers import * + + +class VertexMaterialGroup(): + name = 'VertexMaterial' + + @staticmethod + def create(node_tree, name, vm_info, shader): + instance = node_tree.nodes.new(type='ShaderNodeGroup') + instance.location = (0, 300) + instance.width = 300 + # TODO: depending on prelit type + instance.node_tree = bpy.data.node_groups['VertexMaterial'] + instance.label = name + + instance.inputs['Diffuse'].default_value = vm_info.diffuse.to_vector_rgba() + instance.inputs['Ambient'].default_value = vm_info.ambient.to_vector_rgba() + instance.inputs['Specular'].default_value = vm_info.specular.to_vector_rgba() + instance.inputs['Emissive'].default_value = vm_info.emissive.to_vector_rgba() + instance.inputs['Shininess'].default_value = vm_info.shininess + instance.inputs['Opacity'].default_value = vm_info.shininess + instance.inputs['Translucency'].default_value = vm_info.shininess + + instance.inputs['DepthCompare'].default_value = shader.depth_compare + instance.inputs['DepthMask'].default_value = shader.depth_mask + instance.inputs['ColorMask'].default_value = shader.color_mask + instance.inputs['DestBlend'].default_value = shader.dest_blend + instance.inputs['FogFunc'].default_value = shader.fog_func + instance.inputs['PriGradient'].default_value = shader.pri_gradient + instance.inputs['SecGradient'].default_value = shader.sec_gradient + instance.inputs['SrcBlend'].default_value = shader.src_blend + instance.inputs['DetailColorFunc'].default_value = shader.detail_color_func + instance.inputs['DetailAlphaFunc'].default_value = shader.detail_alpha_func + instance.inputs['Preset'].default_value = shader.shader_preset + instance.inputs['AlphaTest'].default_value = shader.alpha_test + instance.inputs['PostDetailColorFunc'].default_value = shader.post_detail_color_func + instance.inputs['PostDetailAlphaFunc'].default_value = shader.post_detail_alpha_func + + return instance + + @staticmethod + def register(name): + group = bpy.data.node_groups.new(name, 'ShaderNodeTree') + node_tree = group + node_tree.name = name + links = node_tree.links + + # create group inputs + group_inputs = group.nodes.new('NodeGroupInput') + group_inputs.location = (-350,0) + group.inputs.new('NodeSocketColor', 'Diffuse') + group.inputs['Diffuse'].default_value = (0.8, 0.8, 0.8, 1.0) + group.inputs.new('NodeSocketFloat', 'DiffuseAlpha') + group.inputs['DiffuseAlpha'].default_value = 1.0 + addInputInt(group, 'DestBlend', max=1) + group.inputs.new('NodeSocketColor', 'Ambient') + group.inputs['Ambient'].default_value = (0.8, 0.8, 0.8, 1.0) + group.inputs.new('NodeSocketColor', 'Specular') + group.inputs['Specular'].default_value = (0.8, 0.8, 0.8, 1.0) + group.inputs.new('NodeSocketColor', 'Emissive') + group.inputs['Emissive'].default_value = (0.8, 0.8, 0.8, 1.0) + group.inputs.new('NodeSocketFloat', 'Shininess') + group.inputs.new('NodeSocketFloat', 'Opacity') + group.inputs.new('NodeSocketFloat', 'Translucency') + + addInputInt(group, 'DepthCompare') + addInputInt(group, 'DepthMask') + addInputInt(group, 'ColorMask') + addInputInt(group, 'FogFunc') + addInputInt(group, 'PriGradient') + addInputInt(group, 'SecGradient') + addInputInt(group, 'SrcBlend') + addInputInt(group, 'Texturing') + addInputInt(group, 'DetailColorFunc') + addInputInt(group, 'DetailAlphaFunc') + addInputInt(group, 'Preset') + addInputInt(group, 'AlphaTest') + addInputInt(group, 'PostDetailColorFunc') + addInputInt(group, 'PostDetailAlphaFunc') + + # create group outputs + group_outputs = group.nodes.new('NodeGroupOutput') + group_outputs.location = (300,0) + group.outputs.new('NodeSocketShader', 'BSDF') + + # create and link nodes + alpha_pipeline = node_tree.nodes.new(type='ShaderNodeGroup') + alpha_pipeline.location = (-100, 0) + alpha_pipeline.node_tree = bpy.data.node_groups['AlphaPipeline'] + links.new(group_inputs.outputs['Diffuse'], alpha_pipeline.inputs['Diffuse']) + links.new(group_inputs.outputs['DiffuseAlpha'], alpha_pipeline.inputs['Alpha']) + links.new(group_inputs.outputs['DestBlend'], alpha_pipeline.inputs['DestBlend']) + + shader = create_specular_shader_node(node_tree) + shader.location = (100, 0) + shader.inputs['Normal'].hide = True + + links.new(group_inputs.outputs['Diffuse'], shader.inputs['Base Color']) + links.new(group_inputs.outputs['Specular'], shader.inputs['Specular']) + links.new(group_inputs.outputs['Shininess'], shader.inputs['Roughness']) + links.new(group_inputs.outputs['Emissive'], shader.inputs['Emissive Color']) + links.new(alpha_pipeline.outputs['Alpha'], shader.inputs['Transparency']) + links.new(shader.outputs['BSDF'], group_outputs.inputs['BSDF']) + + +class PrelitUnlitGroup(VertexMaterialGroup): + name = 'PrelitUnlit' + +class PrelitVertexGroup(VertexMaterialGroup): + name = 'PrelitVertex' + +class PrelitLightmapMultiPassGroup(VertexMaterialGroup): + name = 'PrelitLightmapMultiPass' + +class PrelitLightmapMultiTextureGroup(VertexMaterialGroup): + name = 'PrelitLightmapMultiTextue' \ No newline at end of file diff --git a/io_mesh_w3d/common/utils/NodeShaderWrapper.py b/io_mesh_w3d/common/utils/NodeShaderWrapper.py deleted file mode 100644 index 63f53512..00000000 --- a/io_mesh_w3d/common/utils/NodeShaderWrapper.py +++ /dev/null @@ -1,66 +0,0 @@ -# -# Written by Stephan Vedder and Michael Schnabel - -import bpy - -def get_material_shader(material): - return material.get('shader', None) - -def get_material_textures(material): - textures = dict() - - node_tree = material.node_tree - nodes = node_tree.nodes - # ... - -def create_texture_node(node_tree, tex_path): - node = node_tree.nodes.new('ShaderNodeTexImage') - node.name = 'TestTexture' - - node.color = (1, 0, 0) - node.use_custom_color = True - - node.alpha_mode = 'CHANNEL_PACKED' - - node.image = image - return node - -def set_node_position(node, x, y): - node.location = Vector((x * 300.0, y * -300.0)) - -def create_shader(name): - shader = bpy.data.materials.new(name) - #shader['shader'] = ?? - - shader.use_nodes = True - shader.use_backface_culling = True - shader.shadow_method = 'CLIP' - shader.blend_method = 'CLIP' - - node_tree = shader.node_tree - nodes = node_tree.nodes - links = node_tree.links - - shader_root = nodes.get('Principled BSDF') - - diffuse_tex = create_texture_node(node_tree, name) - set_node_pos(diffuse_tex, -5, 0) - - links.new(diffuse_tex.outputs['Color'], shader_root.inputs['Base Color']) - links.new(albedo_texture.outputs['Alpha'], shader_root.inputs['Alpha']) - - #specular - - #separate_rgb = node_tree.nodes.new(type="ShaderNodeSeparateRGB") - #set_node_pos(separate_rgb, -4, 1) - #links.new(material_texture.outputs['Color'], separate_rgb.inputs['Image']) - # links.new(separate_rgb.outputs['R'], shader_root.inputs['Specular']) # material.R used for custom mask? - #links.new(separate_rgb.outputs['G'], shader_root.inputs['Specular']) - #links.new(separate_rgb.outputs['B'], shader_root.inputs['Metallic']) - #links.new(material_texture.outputs['Alpha'], shader_root.inputs['Roughness']) - - # normal - - normal_texture.image.colorspace_settings.is_data = True - - return shader \ No newline at end of file diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index dc4c9b2c..16f41f6f 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -5,223 +5,12 @@ import bmesh from bpy_extras import node_shader_utils +from io_mesh_w3d.common.node_groups.vertex_material import * +from io_mesh_w3d.common.node_groups.normal_mapped import * +from io_mesh_w3d.common.node_groups.helpers import * from io_mesh_w3d.common.utils.helpers import * from io_mesh_w3d.w3d.structs.mesh_structs.vertex_material import * - #node.color = (1, 0, 0) - #node.use_custom_color = True - #node.name = 'Test' - #node.label - -def register_w3d_material_node_group(): - group = bpy.data.node_groups.new('W3DMaterial', 'ShaderNodeTree') - node_tree = group - links = node_tree.links - - # create group inputs - group_inputs = group.nodes.new('NodeGroupInput') - group_inputs.location = (-350,0) - group.inputs.new('NodeSocketColor', 'Diffuse') - group.inputs.new('NodeSocketFloat', 'Alpha') - group.inputs['Alpha'].default_value = 1.0 - group.inputs.new('NodeSocketColor', 'Diffuse2') - group.inputs.new('NodeSocketFloat', 'Alpha2') - group.inputs.new('NodeSocketInt', 'DestBlend') - group.inputs['DestBlend'].default_value = 0 - group.inputs['DestBlend'].min_value = 0 - group.inputs['DestBlend'].max_value = 1 - group.inputs.new('NodeSocketColor', 'Specular') - group.inputs.new('NodeSocketFloat', 'Roughness') - group.inputs.new('NodeSocketColor', 'Emissive') - group.inputs.new('NodeSocketColor', 'Normal') - group.inputs.new('NodeSocketFloat', 'Strength') - - - # create group outputs - group_outputs = group.nodes.new('NodeGroupOutput') - group_outputs.location = (300,0) - group.outputs.new('NodeSocketShader', 'BSDF') - - # create and link nodes - mix = create_rgb_mix_node(node_tree) - mix.location = (-100, 200) - links.new(group_inputs.outputs['Diffuse'], mix.inputs['Color1']) - links.new(group_inputs.outputs['Diffuse2'], mix.inputs['Color2']) - links.new(group_inputs.outputs['Alpha2'], mix.inputs['Fac']) - - alpha_pipeline = node_tree.nodes.new(type='ShaderNodeGroup') - alpha_pipeline.location = (-100, 0) - alpha_pipeline.node_tree = bpy.data.node_groups['W3DAlphaPipeline'] - links.new(group_inputs.outputs['Diffuse'], alpha_pipeline.inputs['Diffuse']) - links.new(group_inputs.outputs['Alpha'], alpha_pipeline.inputs['Alpha']) - links.new(group_inputs.outputs['DestBlend'], alpha_pipeline.inputs['DestBlend']) - - normal = create_normal_map_node(node_tree) - normal.location = (-100, -200) - links.new(group_inputs.outputs['Normal'], normal.inputs['Color']) - links.new(group_inputs.outputs['Strength'], normal.inputs['Strength']) - - shader = create_specular_shader_node(node_tree) - shader.location = (100, 0) - links.new(mix.outputs['Color'], shader.inputs['Base Color']) - links.new(group_inputs.outputs['Specular'], shader.inputs['Specular']) - links.new(group_inputs.outputs['Roughness'], shader.inputs['Roughness']) - links.new(group_inputs.outputs['Emissive'], shader.inputs['Emissive Color']) - links.new(alpha_pipeline.outputs['Alpha'], shader.inputs['Transparency']) - links.new(normal.outputs['Normal'], shader.inputs['Normal']) - links.new(shader.outputs['BSDF'], group_outputs.inputs['BSDF']) - - -def register_alpha_node_group(): - group = bpy.data.node_groups.new('W3DAlphaPipeline', 'ShaderNodeTree') - node_tree = group - links = node_tree.links - - # create group inputs - group_inputs = group.nodes.new('NodeGroupInput') - group_inputs.location = (-500,0) - group.inputs.new('NodeSocketColor', 'Diffuse') - group.inputs.new('NodeSocketFloat', 'Alpha') - group.inputs['Alpha'].default_value = 1.0 - group.inputs.new('NodeSocketInt', 'DestBlend') - group.inputs['DestBlend'].default_value = 0 - group.inputs['DestBlend'].min_value = 0 - group.inputs['DestBlend'].max_value = 1 - - # create group outputs - group_outputs = group.nodes.new('NodeGroupOutput') - group_outputs.location = (500,0) - group.outputs.new('NodeSocketFloat', 'Alpha') - - # default texture alpha - compare_1 = create_math_node(node_tree, mode='COMPARE') - compare_1.location = (-200, 100) - compare_1.inputs[0].default_value = 0 - links.new(group_inputs.outputs['DestBlend'], compare_1.inputs[1]) - links.new(group_inputs.outputs['Alpha'], compare_1.inputs[2]) - - # v of diffuse - seperate_hsv = create_seperate_hsv_node(node_tree) - seperate_hsv.location = (-300, -100) - links.new(group_inputs.outputs['Diffuse'], seperate_hsv.inputs['Color']) - - compare_2 = create_math_node(node_tree, mode='COMPARE') - compare_2.location = (-100, -100) - compare_2.inputs[0].default_value = 1 - links.new(group_inputs.outputs['DestBlend'], compare_2.inputs[1]) - links.new(seperate_hsv.outputs['V'], compare_2.inputs[2]) - - # both - add_node = create_math_node(node_tree, mode='ADD') - add_node.location = (100, 0) - links.new(compare_1.outputs['Value'], add_node.inputs[0]) - links.new(compare_2.outputs['Value'], add_node.inputs[1]) - - subtract_node = create_math_node(node_tree, mode='SUBTRACT') - subtract_node.location = (300, 0) - subtract_node.inputs[0].default_value = 1.0 - links.new(add_node.outputs['Value'], subtract_node.inputs[1]) - links.new(subtract_node.outputs['Value'], group_outputs.inputs['Alpha']) - - -def get_connected_nodes(links, node, input, types=[]): - nodes = [] - for link in links: - #print(link.to_node) - #print(link.to_socket) - if link.to_node == node and link.to_socket.identifier == input: - # and link.from_socket in outputs: - # and type(node) == bpy.types.ShaderNodeTexture.... - # and node.inputs[''].is_linked - nodes.append(link.from_node) - - for node in nodes: - print('###') - print(node.bl_idname) - print(node.name) - return nodes - - -def create_specular_shader_node(node_tree): - # inputs: Base Color, Specular, Roughness, Emissive Color, Transparency, - # Normal, Clear Coat, Clear Coat Radius, Clear Coat Normal, Ambient Occlusion - # outputs: BSDF - - node = node_tree.nodes.new('ShaderNodeEeveeSpecular') - node.label = 'Shader' - # hide unused inputs - node.inputs['Clear Coat'].hide = True - node.inputs['Clear Coat Roughness'].hide = True - node.inputs['Clear Coat Normal'].hide = True - node.inputs['Ambient Occlusion'].hide = True - return node - - -def create_texture_node(node_tree, texture): - # inputs: Vector - # outputs: Color, Alpha - - node = node_tree.nodes.new('ShaderNodeTexImage') - #node.color_mapping - #node.extension # interpolation past bounds - node.image = texture - #node.image_user - #node.interpolation - #node.projection - #node.projection_blend - #node.texture_mapping - return node - -def create_uv_map_node(node_tree): - # outputs: UV - - node = node_tree.nodes.new('ShaderNodeUVMap') - #node.uv_map = 'uvmapname' - return node - -def create_math_node(node_tree, mode='SUBTRACT'): - # inputs: Value, Value - # outputs: Value - - node = node_tree.nodes.new('ShaderNodeMath') - node.operation = mode - #node.clamp = False - return node - -def create_rgb_mix_node(node_tree): - # inputs: Fac, Color1, Color2 - # outputs: Color - - node = node_tree.nodes.new('ShaderNodeMixRGB') - #node.blend_type - #node.use_alpha - #node.use_clamp - return node - -def create_normal_map_node(node_tree): - # inputs: Strength, Color - # outputs: Normal - - node = node_tree.nodes.new('ShaderNodeNormalMap') - node.space = 'TANGENT' - #node.uv_map = 'uvmapname' - return node - -def create_seperate_hsv_node(node_tree): - # inputs: Color - # outputs: H, S, V - - node = node_tree.nodes.new('ShaderNodeSeparateHSV') - return node - -def create_rgb_node(node_tree): - # outputs: Color - - node = node_tree.nodes.new('ShaderNodeRGB') - return node - - - def get_or_create_uv_layer(mesh, b_mesh, triangles, tx_coords): for uv_layer in mesh.uv_layers: @@ -242,7 +31,6 @@ def get_or_create_uv_layer(mesh, b_mesh, triangles, tx_coords): return uv_layer.name - def create_material_passes(context, base_struct, mesh, triangles): b_mesh = bmesh.new() b_mesh.from_mesh(mesh) @@ -254,7 +42,8 @@ def create_material_passes(context, base_struct, mesh, triangles): shader_materials = [] tx_coords = [] - #TODO: create vert_mat - shader - texture combinations + #TODO: create vert_mat - shader - texture combinations + # and support different materials for each triangle for vert_mat_id in mat_pass.vertex_material_ids: vert_materials.append(base_struct.vert_materials[vert_mat_id]) @@ -296,11 +85,9 @@ def create_material_passes(context, base_struct, mesh, triangles): ########################################################################## def create_vertex_material(context, mesh, b_mesh, triangles, vert_mat, shader, texture_struct, tx_coords): - material = bpy.data.materials.new(mesh.name) + material = bpy.data.materials.new(mesh.name + '.' + vert_mat.vm_name) mesh.materials.append(material) - material.material_type = 'VERTEX_MATERIAL' - material.prelit_type = 'PRELIT_UNLIT' material.use_nodes = True material.shadow_method = 'CLIP' material.blend_method = 'BLEND' @@ -318,43 +105,27 @@ def create_vertex_material(context, mesh, b_mesh, triangles, vert_mat, shader, t if attributes & DEPTH_CUE_TO_ALPHA: material.attributes.add('DEPTH_CUE_TO_ALPHA') - # TODO: map these to shader node properties - material.ambient = vert_mat.vm_info.ambient.to_vector_rgba() - material.translucency = vert_mat.vm_info.translucency - material.opacity = vert_mat.vm_info.opacity - + # TODO: translate those to shader properties material.vm_args_0 = vert_mat.vm_args_0 material.vm_args_1 = vert_mat.vm_args_1 - set_shader_properties(material, shader) - - # get or create node group node_tree = material.node_tree links = node_tree.links - # delete principled bsdf - principled_bsdf = node_tree.nodes.get('Principled BSDF') - node_tree.nodes.remove(principled_bsdf) + node_tree.nodes.remove(node_tree.nodes.get('Principled BSDF')) - inst = node_tree.nodes.new(type='ShaderNodeGroup') - inst.location = (0, 300) - inst.node_tree = bpy.data.node_groups['W3DMaterial'] - inst.label = vert_mat.vm_name - - inst.inputs['Specular'].default_value = vert_mat.vm_info.specular.to_vector_rgba() - inst.inputs['Roughness'].default_value = vert_mat.vm_info.shininess - inst.inputs['Emissive'].default_value = vert_mat.vm_info.emissive.to_vector_rgba() + instance = VertexMaterialGroup.create(node_tree, vert_mat.vm_name, vert_mat.vm_info, shader) output = node_tree.nodes.get('Material Output') - links.new(inst.outputs['BSDF'], output.inputs['Surface']) + links.new(instance.outputs['BSDF'], output.inputs['Surface']) if texture_struct is not None: texture = find_texture(context, texture_struct.file, texture_struct.id) texture_node = create_texture_node(node_tree, texture) texture_node.location = (-250, 0) - links.new(texture_node.outputs['Color'], inst.inputs['Diffuse']) - links.new(texture_node.outputs['Alpha'], inst.inputs['Alpha']) + links.new(texture_node.outputs['Color'], instance.inputs['Diffuse']) + links.new(texture_node.outputs['Alpha'], instance.inputs['DiffuseAlpha']) uv_layer = get_or_create_uv_layer(mesh, b_mesh, triangles, tx_coords) @@ -370,173 +141,27 @@ def create_vertex_material(context, mesh, b_mesh, triangles, vert_mat, shader, t def create_shader_material(context, mesh, b_mesh, triangles, shader_mat, tx_coords): - material = bpy.data.materials.new(mesh.name) + mat_name = shader_mat.header.type_name + + # TODO: verify that + #if mat_name in bpy.data.materials: + # mesh.materials.append(bpy.data.materials[mat_name]) + # return + + material = bpy.data.materials.new(mat_name) mesh.materials.append(material) - material.material_type = 'SHADER_MATERIAL' material.use_nodes = True material.blend_method = 'BLEND' material.show_transparent_back = False - if shader_mat.header.technique is not None: - material.technique = shader_mat.header.technique - - # get or create node group node_tree = material.node_tree links = node_tree.links - # delete principled bsdf - principled_bsdf = node_tree.nodes.get('Principled BSDF') - node_tree.nodes.remove(principled_bsdf) - - inst = node_tree.nodes.new(type='ShaderNodeGroup') - inst.location = (0, 300) - inst.node_tree = bpy.data.node_groups['W3DMaterial'] - inst.label = shader_mat.header.type_name - - output = node_tree.nodes.get('Material Output') - links.new(inst.outputs['BSDF'], output.inputs['Surface']) + node_tree.nodes.remove(node_tree.nodes.get('Principled BSDF')) uv_layer = get_or_create_uv_layer(mesh, b_mesh, triangles, tx_coords) - for prop in shader_mat.properties: - if prop.name in ['DiffuseTexture', 'Texture_0'] and prop.value != '': - texture_node = create_texture_node(node_tree, find_texture(context, prop.value)) - texture_node.location = (-550, 600) - links.new(texture_node.outputs['Color'], inst.inputs['Diffuse']) - links.new(texture_node.outputs['Alpha'], inst.inputs['Alpha']) - - uv_node = create_uv_map_node(node_tree) - uv_node.uv_map = uv_layer - uv_node.location = (-750, 600) - links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) - elif prop.name == 'NormalMap' and prop.value != '': - texture_node = create_texture_node(node_tree, find_texture(context, prop.value)) - texture_node.location = (-550, -300) - links.new(texture_node.outputs['Color'], inst.inputs['Normal']) - - uv_node = create_uv_map_node(node_tree) - uv_node.uv_map = uv_layer - uv_node.location = (-750, -300) - links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) - elif prop.name == 'BumpScale': - inst.inputs['Strength'].default_value = prop.value - elif prop.name == 'SpecMap' and prop.value != '': - texture_node = create_texture_node(node_tree, find_texture(context, prop.value)) - texture_node.location = (-550, 0) - links.new(texture_node.outputs['Color'], inst.inputs['Specular']) - - uv_node = create_uv_map_node(node_tree) - uv_node.uv_map = uv_layer - uv_node.location = (-750, 0) - links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) - elif prop.name == 'SpecularExponent' or prop.name == 'Shininess': - inst.inputs['Roughness'].default_value = prop.value / 200.0 - elif prop.name == 'DiffuseColor' or prop.name == 'ColorDiffuse': - material.diffuse_color = prop.to_rgba() - elif prop.name == 'SpecularColor' or prop.name == 'ColorSpecular': - material.specular_color = prop.to_rgb() - elif prop.name == 'CullingEnable': - material.use_backface_culling = prop.value - elif prop.name == 'Texture_1': - texture_node = create_texture_node(node_tree, find_texture(context, prop.value)) - texture_node.location = (-550, 300) - links.new(texture_node.outputs['Color'], inst.inputs['Diffuse2']) - links.new(texture_node.outputs['Alpha'], inst.inputs['Alpha2']) - - uv_node = create_uv_map_node(node_tree) - uv_node.uv_map = uv_layer - uv_node.location = (-750, 300) - links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) - - # all props below have no effect on shading -> custom properties for roundtrip purpose - elif prop.name == 'AmbientColor' or prop.name == 'ColorAmbient': - material.ambient = prop.to_rgba() - elif prop.name == 'EmissiveColor' or prop.name == 'ColorEmissive': - material.emission = prop.to_rgba() - elif prop.name == 'Opacity': - material.opacity = prop.value - elif prop.name == 'AlphaTestEnable': - material.alpha_test = prop.value - elif prop.name == 'BlendMode': # is blend_method ? - material.blend_mode = prop.value - elif prop.name == 'BumpUVScale': - material.bump_uv_scale = prop.value.xy - elif prop.name == 'EdgeFadeOut': - material.edge_fade_out = prop.value - elif prop.name == 'DepthWriteEnable': - material.depth_write = prop.value - elif prop.name == 'Sampler_ClampU_ClampV_NoMip_0': - material.sampler_clamp_uv_no_mip_0 = prop.value - elif prop.name == 'Sampler_ClampU_ClampV_NoMip_1': - material.sampler_clamp_uv_no_mip_1 = prop.value - elif prop.name == 'NumTextures': - material.num_textures = prop.value # is 1 if texture_0 and texture_1 are set - elif prop.name == 'SecondaryTextureBlendMode': - material.secondary_texture_blend_mode = prop.value - elif prop.name == 'TexCoordMapper_0': - material.tex_coord_mapper_0 = prop.value - elif prop.name == 'TexCoordMapper_1': - material.tex_coord_mapper_1 = prop.value - elif prop.name == 'TexCoordTransform_0': - material.tex_coord_transform_0 = prop.value - elif prop.name == 'TexCoordTransform_1': - material.tex_coord_transform_1 = prop.value - elif prop.name == 'EnvironmentTexture': - material.environment_texture = prop.value - elif prop.name == 'EnvMult': - material.environment_mult = prop.value - elif prop.name == 'RecolorTexture': - material.recolor_texture = prop.value - elif prop.name == 'RecolorMultiplier': - material.recolor_mult = prop.value - elif prop.name == 'UseRecolorColors': - material.use_recolor = prop.value - elif prop.name == 'HouseColorPulse': - material.house_color_pulse = prop.value - elif prop.name == 'ScrollingMaskTexture': - material.scrolling_mask_texture = prop.value - elif prop.name == 'TexCoordTransformAngle_0': - material.tex_coord_transform_angle = prop.value - elif prop.name == 'TexCoordTransformU_0': - material.tex_coord_transform_u_0 = prop.value - elif prop.name == 'TexCoordTransformV_0': - material.tex_coord_transform_v_0 = prop.value - elif prop.name == 'TexCoordTransformU_1': - material.tex_coord_transform_u_1 = prop.value - elif prop.name == 'TexCoordTransformV_1': - material.tex_coord_transform_v_1 = prop.value - elif prop.name == 'TexCoordTransformU_2': - material.tex_coord_transform_u_2 = prop.value - elif prop.name == 'TexCoordTransformV_2': - material.tex_coord_transform_v_2 = prop.value - elif prop.name == 'TextureAnimation_FPS_NumPerRow_LastFrame_FrameOffset_0': - material.tex_ani_fps_NPR_lastFrame_frameOffset_0 = prop.value - elif prop.name == 'IonHullTexture': - material.ion_hull_texture = prop.value - elif prop.name == 'MultiTextureEnable': - material.multi_texture_enable = prop.value - else: - context.error('shader property not implemented: ' + prop.name) + instance = NormalMappedGroup.create(context, node_tree, shader_mat, uv_layer) - -########################################################################## -# set shader properties -########################################################################## - - -def set_shader_properties(material, shader): - material.shader.depth_compare = shader.depth_compare - material.shader.depth_mask = shader.depth_mask - material.shader.color_mask = shader.color_mask - material.shader.dest_blend = shader.dest_blend - material.shader.fog_func = shader.fog_func - material.shader.pri_gradient = shader.pri_gradient - material.shader.sec_gradient = shader.sec_gradient - material.shader.src_blend = shader.src_blend - material.shader.texturing = shader.texturing - material.shader.detail_color_func = shader.detail_color_func - material.shader.detail_alpha_func = shader.detail_alpha_func - material.shader.shader_preset = shader.shader_preset - material.shader.alpha_test = shader.alpha_test - material.shader.post_detail_color_func = shader.post_detail_color_func - material.shader.post_detail_alpha_func = shader.post_detail_alpha_func \ No newline at end of file + output = node_tree.nodes.get('Material Output') + links.new(instance.outputs['BSDF'], output.inputs['Surface']) diff --git a/io_mesh_w3d/custom_properties.py b/io_mesh_w3d/custom_properties.py index 13549026..b6964c9d 100644 --- a/io_mesh_w3d/custom_properties.py +++ b/io_mesh_w3d/custom_properties.py @@ -55,26 +55,6 @@ # Material ########################################################################## - -Material.material_type = EnumProperty( - name='Material Type', - description='defines the type of the material', - items=[ - ('SHADER_MATERIAL', 'Shader Material', 'desc: todo'), - ('VERTEX_MATERIAL', 'Vertex Material', 'desc: todo'), - ('PRELIT_MATERIAL', 'Prelit Material', 'desc: todo')], - default='SHADER_MATERIAL') - -Material.prelit_type = EnumProperty( - name='Prelit Type', - description='defines the prelit type of the vertex material', - items=[ - ('PRELIT_UNLIT', 'Prelit Unlit', 'desc: todo'), - ('PRELIT_VERTEX', 'Prelit Vertex', 'desc: todo'), - ('PRELIT_LIGHTMAP_MULTI_PASS', 'Prelit Lightmap multi Pass', 'desc: todo'), - ('PRELIT_LIGHTMAP_MULTI_TEXTURE', 'Prelit Lightmap multi Texture', 'desc: todo')], - default='PRELIT_UNLIT') - Material.attributes = EnumProperty( name='attributes', description='Attributes that define the behaviour of this material', @@ -125,13 +105,6 @@ ('31', 'UnderwaterTiberiumDirt', 'desc: todo')], default='13') - -Material.translucency = FloatProperty( - name='Translucency', - default=0.0, - min=0.0, max=1.0, - description='Translucency property') - Material.vm_args_0 = StringProperty( name='vm_args_0', description='Vertex Material Arguments 0', @@ -140,249 +113,4 @@ Material.vm_args_1 = StringProperty( name='vm_args_1', description='Vertex Material Arguments 1', - default='') - -Material.technique = IntProperty( - name='Technique', - description='Dont know yet', - default=0, - min=0, - max=1) - -Material.ambient = FloatVectorProperty( - name='Ambient', - subtype='COLOR', - size=4, - default=(1.0, 1.0, 1.0, 0.0), - min=0.0, max=1.0, - description='Ambient color') - -Material.emission = FloatVectorProperty( - name='Emission', - subtype='COLOR', - size=4, - default=(1.0, 1.0, 1.0, 0.0), - min=0.0, max=1.0, - description='Emission color') - -Material.opacity = FloatProperty( - name='Opacity', - default=0.0, - min=0.0, max=1.0, - description='Opacity property') - -Material.alpha_test = BoolProperty( - name='Alpha test', - description='Enable the alpha test', - default=True) - -Material.blend_mode = IntProperty( - name='Blend mode', - description='Which blend mode should be used', - default=0, - min=0, - max=5) - -Material.bump_uv_scale = FloatVectorProperty( - name='Bump UV Scale', - subtype='TRANSLATION', - size=2, - default=(0.0, 0.0), - min=0.0, max=1.0, - description='Bump uv scale') - -Material.edge_fade_out = IntProperty( - name='Edge fade out', - description='TODO', - default=0, - min=0, - max=5) - -Material.depth_write = BoolProperty( - name='Depth write', - description='Todo', - default=False) - -Material.sampler_clamp_uv_no_mip_0 = FloatVectorProperty( - name='Sampler clamp UV no MIP 0', - subtype='TRANSLATION', - size=4, - default=(0.0, 0.0, 0.0, 0.0), - min=0.0, max=1.0, - description='Sampler clampU clampV no mipmap 0') - -Material.sampler_clamp_uv_no_mip_1 = FloatVectorProperty( - name='Sampler clamp UV no MIP 1', - subtype='TRANSLATION', - size=4, - default=(0.0, 0.0, 0.0, 0.0), - min=0.0, max=1.0, - description='Sampler clampU clampV no mipmap 1') - -Material.num_textures = IntProperty( - name='NumTextures', - description='TODO', - default=0, - min=0, - max=5) - -Material.texture_1 = StringProperty( - name='Texture 1', - description='TODO', - default='') - -Material.secondary_texture_blend_mode = IntProperty( - name='Secondary texture blend mode', - description='TODO', - default=0, - min=0, - max=5) - -Material.tex_coord_mapper_0 = IntProperty( - name='TexCoord mapper 0', - description='TODO', - default=0, - min=0, - max=5) - -Material.tex_coord_mapper_1 = IntProperty( - name='TexCoord mapper 1', - description='TODO', - default=0, - min=0, - max=5) - -Material.tex_coord_transform_0 = FloatVectorProperty( - name='TexCoord transform 0', - subtype='TRANSLATION', - size=4, - default=(0.0, 0.0, 0.0, 0.0), - min=0.0, max=1.0, - description='TODO') - -Material.tex_coord_transform_1 = FloatVectorProperty( - name='TexCoord transform 1', - subtype='TRANSLATION', - size=4, - default=(0.0, 0.0, 0.0, 0.0), - min=0.0, max=1.0, - description='TODO') - -Material.environment_texture = StringProperty( - name='Environment texture', - description='TODO', - default='') - -Material.environment_mult = FloatProperty( - name='Environment mult', - default=0.0, - min=0.0, max=1.0, - description='Todo') - -Material.recolor_texture = StringProperty( - name='Recolor texture', - description='TODO', - default='') - -Material.recolor_mult = FloatProperty( - name='Recolor mult', - default=0.0, - min=0.0, max=1.0, - description='Todo') - -Material.use_recolor = BoolProperty( - name='Use recolor colors', - description='Todo', - default=False) - -Material.house_color_pulse = BoolProperty( - name='House color pulse', - description='Todo', - default=False) - -Material.scrolling_mask_texture = StringProperty( - name='Scrolling mask texture', - description='TODO', - default='') - -Material.tex_coord_transform_angle = FloatProperty( - name='Texture coord transform angle', - default=0.0, - min=0.0, max=1.0, - description='Todo') - -Material.tex_coord_transform_u_0 = FloatProperty( - name='Texture coord transform u 0', - default=0.0, - min=0.0, max=1.0, - description='Todo') - -Material.tex_coord_transform_v_0 = FloatProperty( - name='Texture coord transform v 0', - default=0.0, - min=0.0, max=1.0, - description='Todo') - -Material.tex_coord_transform_u_1 = FloatProperty( - name='Texture coord transform u 0', - default=0.0, - min=0.0, max=1.0, - description='Todo') - -Material.tex_coord_transform_v_1 = FloatProperty( - name='Texture coord transform v 0', - default=0.0, - min=0.0, max=1.0, - description='Todo') - -Material.tex_coord_transform_u_2 = FloatProperty( - name='Texture coord transform u 0', - default=0.0, - min=0.0, max=1.0, - description='Todo') - -Material.tex_coord_transform_v_2 = FloatProperty( - name='Texture coord transform v 0', - default=0.0, - min=0.0, max=1.0, - description='Todo') - -Material.tex_ani_fps_NPR_lastFrame_frameOffset_0 = FloatVectorProperty( - name='TextureAnimation FPS NumPerRow LastFrame FrameOffset 0', - subtype='TRANSLATION', - size=4, - default=(0.0, 0.0, 0.0, 0.0), - min=0.0, max=1.0, - description='TODO') - -Material.ion_hull_texture = StringProperty( - name='Ion hull texture', - description='TODO', - default='') - -Material.multi_texture_enable = BoolProperty( - name='Multi texture enable', - description='Todo', - default=False) - -########################################################################## -# Material.Shader -########################################################################## - - -class ShaderProperties(PropertyGroup): - depth_compare: bpy.props.IntProperty(min=0, max=255) - depth_mask: bpy.props.IntProperty(min=0, max=255) - color_mask: bpy.props.IntProperty(min=0, max=255) - dest_blend: bpy.props.IntProperty(min=0, max=255) - fog_func: bpy.props.IntProperty(min=0, max=255) - pri_gradient: bpy.props.IntProperty(min=0, max=255) - sec_gradient: bpy.props.IntProperty(min=0, max=255) - src_blend: bpy.props.IntProperty(min=0, max=255) - texturing: bpy.props.IntProperty(min=0, max=255) - detail_color_func: bpy.props.IntProperty(min=0, max=255) - detail_alpha_func: bpy.props.IntProperty(min=0, max=255) - shader_preset: bpy.props.IntProperty(min=0, max=255) - alpha_test: bpy.props.IntProperty(min=0, max=255) - post_detail_color_func: bpy.props.IntProperty(min=0, max=255) - post_detail_alpha_func: bpy.props.IntProperty(min=0, max=255) \ No newline at end of file + default='') \ No newline at end of file From bbe7634a466dfbd822cd66ad20ca0b8f7891c61c Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Sat, 4 Apr 2020 00:46:57 +0200 Subject: [PATCH 26/62] some more work on various fx shaders --- io_mesh_w3d/__init__.py | 14 +++-- .../common/node_groups/normal_mapped.py | 32 ++++++---- io_mesh_w3d/common/node_groups/objects_gdi.py | 61 +++++++++++++++++++ .../common/node_groups/vertex_material.py | 6 +- .../common/structs/mesh_structs/aabbtree.py | 1 + io_mesh_w3d/common/utils/material_import.py | 14 ++++- 6 files changed, 107 insertions(+), 21 deletions(-) create mode 100644 io_mesh_w3d/common/node_groups/objects_gdi.py diff --git a/io_mesh_w3d/__init__.py b/io_mesh_w3d/__init__.py index a960450a..e1072c18 100644 --- a/io_mesh_w3d/__init__.py +++ b/io_mesh_w3d/__init__.py @@ -295,14 +295,18 @@ def register_node_groups(): AlphaPipeline.register() from io_mesh_w3d.common.node_groups.vertex_material import VertexMaterialGroup, PrelitUnlitGroup, PrelitVertexGroup, PrelitLightmapMultiPassGroup, PrelitLightmapMultiTextureGroup - VertexMaterialGroup.register(VertexMaterialGroup.name) - PrelitUnlitGroup.register(PrelitUnlitGroup.name) - PrelitVertexGroup.register(PrelitVertexGroup.name) - PrelitLightmapMultiPassGroup.register(PrelitLightmapMultiPassGroup.name) - PrelitLightmapMultiTextureGroup.register(PrelitLightmapMultiTextureGroup.name) + VertexMaterialGroup.register() + PrelitUnlitGroup.register() + PrelitVertexGroup.register() + PrelitLightmapMultiPassGroup.register() + PrelitLightmapMultiTextureGroup.register() from io_mesh_w3d.common.node_groups.normal_mapped import NormalMappedGroup NormalMappedGroup.register() + from io_mesh_w3d.common.node_groups.objects_gdi import ObjectsGDIGroup + ObjectsGDIGroup.register() + from io_mesh_w3d.common.node_groups.objects_gdi import ObjectsAlienGroup + ObjectsAlienGroup.register() def register(): for class_ in CLASSES: diff --git a/io_mesh_w3d/common/node_groups/normal_mapped.py b/io_mesh_w3d/common/node_groups/normal_mapped.py index 6a150212..29c8a1c2 100644 --- a/io_mesh_w3d/common/node_groups/normal_mapped.py +++ b/io_mesh_w3d/common/node_groups/normal_mapped.py @@ -7,15 +7,10 @@ class NormalMappedGroup(): + name = 'NormalMapped.fx' @staticmethod - def create(context, node_tree, shader_mat, uv_layer): - instance = node_tree.nodes.new(type='ShaderNodeGroup') - instance.node_tree = bpy.data.node_groups['NormalMapped'] - instance.label = 'NormalMapped.fx' - instance.location = (0, 300) - instance.width = 300 - + def apply_data(context, node_tree, instance, shader_mat, uv_layer): links = node_tree.links if shader_mat.header.technique is not None: @@ -51,14 +46,22 @@ def create(context, node_tree, shader_mat, uv_layer): elif prop.name in ['SpecularExponent', 'BumpScale', 'AlphaTestEnable']: instance.inputs[prop.name].default_value = prop.value else: - print(prop.name + ' -> is not a valid input of NormalMapped.fx') + context.warning(prop.name + ' -> is not a valid input of:' + NormalMappedGroup.name) return instance @staticmethod - def register(): - name = 'NormalMapped' - group = bpy.data.node_groups.new(name, 'ShaderNodeTree') + def create(context, node_tree, shader_mat, uv_layer): + instance = node_tree.nodes.new(type='ShaderNodeGroup') + instance.node_tree = bpy.data.node_groups[NormalMappedGroup.name] + instance.label = NormalMappedGroup.name + instance.location = (0, 300) + instance.width = 300 + + return NormalMappedGroup.apply_data(context, node_tree, instance, shader_mat, uv_layer) + + @staticmethod + def create_inputs_and_links(group, name): node_tree = group node_tree.name = name links = node_tree.links @@ -81,7 +84,6 @@ def register(): group.inputs.new('NodeSocketColor', 'Ambient') group.inputs['Ambient'].default_value = (0.8, 0.8, 0.8, 1.0) group.inputs.new('NodeSocketColor', 'Specular') - group.inputs['Specular'].default_value = (0.8, 0.8, 0.8, 1.0) group.inputs.new('NodeSocketFloat', 'SpecularExponent') # create group outputs @@ -111,3 +113,9 @@ def register(): links.new(alpha_pipeline.outputs['Alpha'], shader.inputs['Transparency']) links.new(normal.outputs['Normal'], shader.inputs['Normal']) links.new(shader.outputs['BSDF'], group_outputs.inputs['BSDF']) + + + @staticmethod + def register(): + group = bpy.data.node_groups.new(NormalMappedGroup.name, 'ShaderNodeTree') + NormalMappedGroup.create_inputs_and_links(group, NormalMappedGroup.name) diff --git a/io_mesh_w3d/common/node_groups/objects_gdi.py b/io_mesh_w3d/common/node_groups/objects_gdi.py new file mode 100644 index 00000000..27a952e8 --- /dev/null +++ b/io_mesh_w3d/common/node_groups/objects_gdi.py @@ -0,0 +1,61 @@ +# +# Written by Stephan Vedder and Michael Schnabel + +import bpy +from io_mesh_w3d.common.node_groups.normal_mapped import * + + +class ObjectsGDIGroup(NormalMappedGroup): + name = 'ObjectsGDI.fx' + + @staticmethod + def create(context, node_tree, shader_mat, uv_layer): + instance = node_tree.nodes.new(type='ShaderNodeGroup') + instance.node_tree = bpy.data.node_groups[ObjectsGDIGroup.name] + instance.label = ObjectsGDIGroup.name + instance.location = (0, 300) + instance.width = 300 + + instance = NormalMappedGroup.apply_data(context, node_tree, instance, shader_mat, uv_layer) + links = node_tree.links + + for prop in shader_mat.properties: + if prop.name == 'RecolorTexture' and prop.value != '': + texture_node = create_texture_node(node_tree, find_texture(context, prop.value)) + texture_node.location = (-550, 600) + links.new(texture_node.outputs['Color'], instance.inputs['RecolorTexture']) + links.new(texture_node.outputs['Alpha'], instance.inputs['RecolorTextureAlpha']) + uv_node = create_uv_map_node(node_tree) + uv_node.uv_map = uv_layer + uv_node.location = (-750, 600) + links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) + if prop.name == 'EnvironmentTexture' and prop.value != '': + texture_node = create_texture_node(node_tree, find_texture(context, prop.value)) + texture_node.location = (-550, 600) + links.new(texture_node.outputs['Color'], instance.inputs['EnvironmentTexture']) + links.new(texture_node.outputs['Alpha'], instance.inputs['EnvironmentTextureAlpha']) + uv_node = create_uv_map_node(node_tree) + uv_node.uv_map = uv_layer + uv_node.location = (-750, 600) + links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) + elif prop.name in ['RecolorTextureAlpha', 'EnvMult']: + instance.inputs[prop.name].default_value = prop.value + else: + context.warning(prop.name + ' -> is not a valid input of: ' + ObjectsGDIGroup.name) + + return instance + + @staticmethod + def register(): + group = bpy.data.node_groups.new(ObjectsGDIGroup.name, 'ShaderNodeTree') + NormalMappedGroup.create_inputs_and_links(group, ObjectsGDIGroup.name) + + group.inputs.new('NodeSocketColor', 'RecolorTexture') + group.inputs.new('NodeSocketFloat', 'RecolorTextureAlpha') + group.inputs.new('NodeSocketColor', 'EnvironmentTexture') + group.inputs.new('NodeSocketColor', 'EnvironmentTextureAlpha') + group.inputs.new('NodeSocketFloat', 'EnvMult') + + +class ObjectsAlienGroup(ObjectsGDIGroup): + name = 'ObjectsAlien.fx' \ No newline at end of file diff --git a/io_mesh_w3d/common/node_groups/vertex_material.py b/io_mesh_w3d/common/node_groups/vertex_material.py index e15287ec..ad8dba40 100644 --- a/io_mesh_w3d/common/node_groups/vertex_material.py +++ b/io_mesh_w3d/common/node_groups/vertex_material.py @@ -43,10 +43,10 @@ def create(node_tree, name, vm_info, shader): return instance @staticmethod - def register(name): - group = bpy.data.node_groups.new(name, 'ShaderNodeTree') + def register(): + group = bpy.data.node_groups.new(VertexMaterialGroup.name, 'ShaderNodeTree') node_tree = group - node_tree.name = name + node_tree.name = VertexMaterialGroup.name links = node_tree.links # create group inputs diff --git a/io_mesh_w3d/common/structs/mesh_structs/aabbtree.py b/io_mesh_w3d/common/structs/mesh_structs/aabbtree.py index e7e9795a..42261a93 100644 --- a/io_mesh_w3d/common/structs/mesh_structs/aabbtree.py +++ b/io_mesh_w3d/common/structs/mesh_structs/aabbtree.py @@ -13,6 +13,7 @@ def __init__(self, node_count=0, poly_count=0): self.node_count = node_count self.poly_count = poly_count # num tris of mesh + @staticmethod def read(io_stream): result = AABBTreeHeader( diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index 16f41f6f..22a351a8 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -7,6 +7,7 @@ from io_mesh_w3d.common.node_groups.vertex_material import * from io_mesh_w3d.common.node_groups.normal_mapped import * +from io_mesh_w3d.common.node_groups.objects_gdi import * from io_mesh_w3d.common.node_groups.helpers import * from io_mesh_w3d.common.utils.helpers import * from io_mesh_w3d.w3d.structs.mesh_structs.vertex_material import * @@ -148,6 +149,12 @@ def create_shader_material(context, mesh, b_mesh, triangles, shader_mat, tx_coor # mesh.materials.append(bpy.data.materials[mat_name]) # return + if mat_name not in [NormalMappedGroup.name, + ObjectsGDIGroup.name, + ObjectsAlienGroup.name]: + context.error('no NodeGroup found for: ' + mat_name) + return + material = bpy.data.materials.new(mat_name) mesh.materials.append(material) material.use_nodes = True @@ -161,7 +168,12 @@ def create_shader_material(context, mesh, b_mesh, triangles, shader_mat, tx_coor uv_layer = get_or_create_uv_layer(mesh, b_mesh, triangles, tx_coords) - instance = NormalMappedGroup.create(context, node_tree, shader_mat, uv_layer) + if mat_name == NormalMappedGroup.name: + instance = NormalMappedGroup.create(context, node_tree, shader_mat, uv_layer) + elif mat_name == ObjectsGDIGroup.name: + instance = ObjectsGDIGroup.create(context, node_tree, shader_mat, uv_layer) + elif mat_name == ObjectsAlienGroup.name: + instance = ObjectsAlienGroup.create(context, node_tree, shader_mat, uv_layer) output = node_tree.nodes.get('Material Output') links.new(instance.outputs['BSDF'], output.inputs['Surface']) From 955194879073533ab91f10d2ef91898ff0da7b53 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Sat, 4 Apr 2020 14:06:11 +0200 Subject: [PATCH 27/62] got the alpha pipeline working --- io_mesh_w3d/__init__.py | 3 + io_mesh_w3d/common/io_xml.py | 112 +++++++++++++++ .../common/utils/node_group_creator.py | 127 ++++++++++++++++++ .../node_group_templates/alpha_pipeline.xml | 37 +++++ io_mesh_w3d/w3x/io_xml.py | 78 +---------- 5 files changed, 283 insertions(+), 74 deletions(-) create mode 100644 io_mesh_w3d/common/io_xml.py create mode 100644 io_mesh_w3d/common/utils/node_group_creator.py create mode 100644 io_mesh_w3d/node_group_templates/alpha_pipeline.xml diff --git a/io_mesh_w3d/__init__.py b/io_mesh_w3d/__init__.py index e1072c18..ec69a4e3 100644 --- a/io_mesh_w3d/__init__.py +++ b/io_mesh_w3d/__init__.py @@ -308,6 +308,9 @@ def register_node_groups(): from io_mesh_w3d.common.node_groups.objects_gdi import ObjectsAlienGroup ObjectsAlienGroup.register() + from io_mesh_w3d.common.utils.node_group_creator import NodeGroupCreator + NodeGroupCreator.create() + def register(): for class_ in CLASSES: bpy.utils.register_class(class_) diff --git a/io_mesh_w3d/common/io_xml.py b/io_mesh_w3d/common/io_xml.py new file mode 100644 index 00000000..3f659c31 --- /dev/null +++ b/io_mesh_w3d/common/io_xml.py @@ -0,0 +1,112 @@ +# +# Written by Stephan Vedder and Michael Schnabel + +import io +import xml.etree.ElementTree as ET +from mathutils import Vector + + +def create_node(self, identifier): + return ET.SubElement(self, identifier) + +def pretty_print(elem, level=0): + i = '\n' + level * ' ' + if elem: + elem.text = i + ' ' + elem.tail = i + for elem in elem: + pretty_print(elem, level + 1) + elem.tail = i + else: + if level and (not elem.tail or not elem.tail.strip()): + elem.tail = i + + +def write(root, path): + pretty_print(root) + xml_spec = "\n" + data = bytes(xml_spec, 'utf-8') + ET.tostring(root) + + file = open(path, 'wb') + file.write(data) + file.close() + + +def strip_namespaces(it): + for _, el in it: + el.tag = el.tag.split('}', 1)[-1] + + +def find_root(context, source): + try: + it = ET.iterparse(source) + strip_namespaces(it) + root = it.root + except BaseException: + if context is None: + print('ERROR: file: ' + source + ' does not contain valid XML data!') + else: + context.error('file: ' + source + ' does not contain valid XML data!') + return None + return root + + +def parse_value(xml_obj, cast_func=str): + return cast_func(xml_obj.text) + + +def create_value(value, parent, identifier): + xml_obj = create_node(parent, identifier) + xml_obj.text = str(value) + + +def parse_objects(parent, name, parse_func, par1=None): + result = [] + objects = parent.findall(name) + if not objects: + return result + for obj in objects: + if par1 is not None: + result.append(parse_func(obj, par1)) + else: + result.append(parse_func(obj)) + return result + + +def create_object_list(parent, name, objects, write_func, par1=None): + xml_objects_list = create_node(parent, name) + for obj in objects: + if par1 is not None: + write_func(obj, xml_objects_list, par1) + else: + write_func(obj, xml_objects_list) + + +def format(value): + return '{:.6f}'.format(value) + + +def parse_vector2(xml_vector2): + return Vector(( + float(xml_vector2.get('X', 0.0)), + float(xml_vector2.get('Y', 0.0)))) + + +def create_vector2(vec2, parent, name): + vector = create_node(parent, name) + vector.set('X', format(vec2.x)) + vector.set('Y', format(vec2.y)) + + +def parse_vector(xml_vector): + return Vector(( + float(xml_vector.get('X', 0.0)), + float(xml_vector.get('Y', 0.0)), + float(xml_vector.get('Z', 0.0)))) + + +def create_vector(vec, parent, name): + vector = create_node(parent, name) + vector.set('X', format(vec.x)) + vector.set('Y', format(vec.y)) + vector.set('Z', format(vec.z)) diff --git a/io_mesh_w3d/common/utils/node_group_creator.py b/io_mesh_w3d/common/utils/node_group_creator.py new file mode 100644 index 00000000..bdc9070d --- /dev/null +++ b/io_mesh_w3d/common/utils/node_group_creator.py @@ -0,0 +1,127 @@ +# +# Written by Stephan Vedder and Michael Schnabel + +import os +import bpy +from os.path import dirname as up +from io_mesh_w3d.common.io_xml import * +from io_mesh_w3d.common.node_groups.helpers import * + + +class NodeGroupCreator(): + @staticmethod + def create_node_group(path): + print(path) + root = find_root(None, path) + if root is None: + print('None') + return + + name = root.get('name') + group = bpy.data.node_groups.new(name, 'ShaderNodeTree') + node_tree = group + links = node_tree.links + + nodes = {} + + for xml_node in root: + if xml_node.tag == 'node': + type = xml_node.get('type') + node = group.nodes.new(type) + x = float(xml_node.get('X', 0.0)) + y = float(xml_node.get('Y', 0.0)) + node.location = (x, y) + nodes[xml_node.get('name')] = node + + if type == 'NodeGroupInput': + for child_node in xml_node: + if child_node.tag != 'input': + continue + input_type = child_node.get('type') + input_name = child_node.get('name') + group.inputs.new(input_type, input_name) + print('created input: ' + input_name) + + #default = child_node.get('default') + #if default is not None: + # if input_type == 'NodeSocketFloat': + # default = float(default) + # elif input_type == 'NodeSocketInt': + # default = int(default) + # group.inputs[input_name].default_value = default + + #min = child_node.get('min') + #if min is not None: + # if input_type == 'NodeSocketFloat': + # min = float(min) + # elif input_type == 'NodeSocketInt': + # min = int(min) + # group.inputs[input_name].min_value = min + + #max = child_node.get('max') + #if max is not None: + # if input_type == 'NodeSocketFloat': + # max = float(max) + # elif input_type == 'NodeSocketInt': + # max = int(max) + # group.inputs[input_name].max_value = max + + elif type == 'NodeGroupOutput': + for child_node in xml_node: + if child_node.tag != 'output': + continue + output_type = child_node.get('type') + output_name = child_node.get('name') + group.outputs.new(input_type, output_name) + print('created output: ' + output_name) + + if type == 'ShaderNodeMath': + node.operation = xml_node.get('mode').upper() + #for child_node in xml_node: + # if child_node.tag != 'input': + # continue + # id = child_node.get('id') + # TODO: support multiple input types + # default = child_node.get('default') + # node.inputs[int(id)] = int(default) + + elif xml_node.tag == 'link': + from_data = xml_node.get('from').split('.') + to_data = xml_node.get('to').split('.') + + from_node = nodes[from_data[0]] + to_node = nodes[to_data[0]] + + from_port = from_data[2] + if from_port.isdigit(): + from_port = int(from_port) + to_port = to_data[2] + if to_port.isdigit(): + to_port = int(to_port) + + print(from_data) + print(to_data) + + if from_data[1] == 'inputs': + from_port = from_node.inputs[from_port] + else: + from_port = from_node.outputs[from_port] + + if to_data[1] == 'inputs': + to_port = to_node.inputs[to_port] + else: + to_port = to_node.outputs[to_port] + + links.new(from_port, to_port) + else: + print('node type: ' + xml_node.tag + ' is not supported') + + @staticmethod + def create(): + dirname = os.path.dirname(__file__) + directory = os.path.join(up(up(dirname)), 'node_group_templates') + + for file in os.listdir(directory): + if file.endswith(".xml"): + NodeGroupCreator.create_node_group(os.path.join(directory, file)) + diff --git a/io_mesh_w3d/node_group_templates/alpha_pipeline.xml b/io_mesh_w3d/node_group_templates/alpha_pipeline.xml new file mode 100644 index 00000000..166b23c8 --- /dev/null +++ b/io_mesh_w3d/node_group_templates/alpha_pipeline.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/io_mesh_w3d/w3x/io_xml.py b/io_mesh_w3d/w3x/io_xml.py index 902f3dcf..9887c0ca 100644 --- a/io_mesh_w3d/w3x/io_xml.py +++ b/io_mesh_w3d/w3x/io_xml.py @@ -2,55 +2,19 @@ # Written by Stephan Vedder and Michael Schnabel import io -import xml.etree.ElementTree as ET +from io_mesh_w3d.common.io_xml import * from mathutils import Vector, Quaternion, Matrix -def create_node(self, identifier): - return ET.SubElement(self, identifier) - - def write_struct(struct, path): root = create_root() struct.create(root) write(root, path) -def pretty_print(elem, level=0): - i = '\n' + level * ' ' - if elem: - elem.text = i + ' ' - elem.tail = i - for elem in elem: - pretty_print(elem, level + 1) - elem.tail = i - else: - if level and (not elem.tail or not elem.tail.strip()): - elem.tail = i - - -def write(root, path): - pretty_print(root) - xml_spec = "\n" - data = bytes(xml_spec, 'utf-8') + ET.tostring(root) - - file = open(path, 'wb') - file.write(data) - file.close() - - -def strip_namespaces(it): - for _, el in it: - el.tag = el.tag.split('}', 1)[-1] - - -def find_root(context, source): - try: - it = ET.iterparse(source) - strip_namespaces(it) - root = it.root - except BaseException: - context.error('file: ' + source + ' does not contain valid XML data!') +def find_asset_root(context, source): + root = find_root(context, source) + if root is None: return None if root.tag != 'AssetDeclaration': @@ -66,40 +30,6 @@ def create_root(): return root -def parse_value(xml_obj, cast_func=str): - return cast_func(xml_obj.text) - - -def create_value(value, parent, identifier): - xml_obj = create_node(parent, identifier) - xml_obj.text = str(value) - - -def parse_objects(parent, name, parse_func, par1=None): - result = [] - objects = parent.findall(name) - if not objects: - return result - for obj in objects: - if par1 is not None: - result.append(parse_func(obj, par1)) - else: - result.append(parse_func(obj)) - return result - - -def create_object_list(parent, name, objects, write_func, par1=None): - xml_objects_list = create_node(parent, name) - for obj in objects: - if par1 is not None: - write_func(obj, xml_objects_list, par1) - else: - write_func(obj, xml_objects_list) - - -def format(value): - return '{:.6f}'.format(value) - def parse_vector2(xml_vector2): return Vector(( From 367613dc715baa6947399a3aade420b086e547d1 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Sat, 4 Apr 2020 15:08:15 +0200 Subject: [PATCH 28/62] got normalMapped.fx template working --- io_mesh_w3d/__init__.py | 31 +++++----- .../common/node_groups/alpha_pipeline.py | 60 ------------------ .../common/node_groups/normal_mapped.py | 62 +------------------ .../common/node_groups/vertex_material.py | 6 +- .../common/utils/node_group_creator.py | 39 ++++++------ .../node_group_templates/alpha_pipeline.xml | 2 +- .../node_group_templates/normal_mapped.xml | 41 ++++++++++++ 7 files changed, 81 insertions(+), 160 deletions(-) delete mode 100644 io_mesh_w3d/common/node_groups/alpha_pipeline.py create mode 100644 io_mesh_w3d/node_group_templates/normal_mapped.xml diff --git a/io_mesh_w3d/__init__.py b/io_mesh_w3d/__init__.py index ec69a4e3..46ea4e47 100644 --- a/io_mesh_w3d/__init__.py +++ b/io_mesh_w3d/__init__.py @@ -1,6 +1,7 @@ # # Written by Stephan Vedder and Michael Schnabel +import os import bpy from bpy_extras.io_utils import ImportHelper, ExportHelper from io_mesh_w3d.export_utils import save @@ -291,25 +292,21 @@ def draw(self, context): def register_node_groups(): - from io_mesh_w3d.common.node_groups.alpha_pipeline import AlphaPipeline - AlphaPipeline.register() + from io_mesh_w3d.common.utils.node_group_creator import NodeGroupCreator + dirname = os.path.dirname(__file__) + directory = os.path.join(dirname, 'node_group_templates') - from io_mesh_w3d.common.node_groups.vertex_material import VertexMaterialGroup, PrelitUnlitGroup, PrelitVertexGroup, PrelitLightmapMultiPassGroup, PrelitLightmapMultiTextureGroup - VertexMaterialGroup.register() - PrelitUnlitGroup.register() - PrelitVertexGroup.register() - PrelitLightmapMultiPassGroup.register() - PrelitLightmapMultiTextureGroup.register() - - from io_mesh_w3d.common.node_groups.normal_mapped import NormalMappedGroup - NormalMappedGroup.register() - from io_mesh_w3d.common.node_groups.objects_gdi import ObjectsGDIGroup - ObjectsGDIGroup.register() - from io_mesh_w3d.common.node_groups.objects_gdi import ObjectsAlienGroup - ObjectsAlienGroup.register() + for file in os.listdir(directory): + if not file.endswith(".xml"): + continue + NodeGroupCreator.create(directory, file) - from io_mesh_w3d.common.utils.node_group_creator import NodeGroupCreator - NodeGroupCreator.create() + from io_mesh_w3d.common.node_groups.vertex_material import VertexMaterialGroup, PrelitUnlitGroup, PrelitVertexGroup, PrelitLightmapMultiPassGroup, PrelitLightmapMultiTextureGroup + VertexMaterialGroup.register(VertexMaterialGroup.name) + PrelitUnlitGroup.register(PrelitUnlitGroup.name) + PrelitVertexGroup.register(PrelitVertexGroup.name) + PrelitLightmapMultiPassGroup.register(PrelitLightmapMultiPassGroup.name) + PrelitLightmapMultiTextureGroup.register(PrelitLightmapMultiTextureGroup.name) def register(): for class_ in CLASSES: diff --git a/io_mesh_w3d/common/node_groups/alpha_pipeline.py b/io_mesh_w3d/common/node_groups/alpha_pipeline.py deleted file mode 100644 index 8da8b486..00000000 --- a/io_mesh_w3d/common/node_groups/alpha_pipeline.py +++ /dev/null @@ -1,60 +0,0 @@ -# -# Written by Stephan Vedder and Michael Schnabel - -import bpy -from io_mesh_w3d.common.node_groups.helpers import * - -class AlphaPipeline(): - name = 'AlphaPipeline' - - @staticmethod - def register(): - group = bpy.data.node_groups.new(AlphaPipeline.name, 'ShaderNodeTree') - node_tree = group - links = node_tree.links - - # create group inputs - group_inputs = group.nodes.new('NodeGroupInput') - group_inputs.location = (-500,0) - group.inputs.new('NodeSocketColor', 'Diffuse') - group.inputs.new('NodeSocketFloat', 'Alpha') - group.inputs['Alpha'].default_value = 1.0 - group.inputs.new('NodeSocketInt', 'DestBlend') - group.inputs['DestBlend'].default_value = 0 - group.inputs['DestBlend'].min_value = 0 - group.inputs['DestBlend'].max_value = 1 - - # create group outputs - group_outputs = group.nodes.new('NodeGroupOutput') - group_outputs.location = (500,0) - group.outputs.new('NodeSocketFloat', 'Alpha') - - # default texture alpha - compare_1 = create_math_node(node_tree, mode='COMPARE') - compare_1.location = (-200, 100) - compare_1.inputs[0].default_value = 0 - links.new(group_inputs.outputs['DestBlend'], compare_1.inputs[1]) - links.new(group_inputs.outputs['Alpha'], compare_1.inputs[2]) - - # v of diffuse - seperate_hsv = create_seperate_hsv_node(node_tree) - seperate_hsv.location = (-300, -100) - links.new(group_inputs.outputs['Diffuse'], seperate_hsv.inputs['Color']) - - compare_2 = create_math_node(node_tree, mode='COMPARE') - compare_2.location = (-100, -100) - compare_2.inputs[0].default_value = 1 - links.new(group_inputs.outputs['DestBlend'], compare_2.inputs[1]) - links.new(seperate_hsv.outputs['V'], compare_2.inputs[2]) - - # both - add_node = create_math_node(node_tree, mode='ADD') - add_node.location = (100, 0) - links.new(compare_1.outputs['Value'], add_node.inputs[0]) - links.new(compare_2.outputs['Value'], add_node.inputs[1]) - - subtract_node = create_math_node(node_tree, mode='SUBTRACT') - subtract_node.location = (300, 0) - subtract_node.inputs[0].default_value = 1.0 - links.new(add_node.outputs['Value'], subtract_node.inputs[1]) - links.new(subtract_node.outputs['Value'], group_outputs.inputs['Alpha']) \ No newline at end of file diff --git a/io_mesh_w3d/common/node_groups/normal_mapped.py b/io_mesh_w3d/common/node_groups/normal_mapped.py index 29c8a1c2..1dabfafd 100644 --- a/io_mesh_w3d/common/node_groups/normal_mapped.py +++ b/io_mesh_w3d/common/node_groups/normal_mapped.py @@ -58,64 +58,4 @@ def create(context, node_tree, shader_mat, uv_layer): instance.location = (0, 300) instance.width = 300 - return NormalMappedGroup.apply_data(context, node_tree, instance, shader_mat, uv_layer) - - @staticmethod - def create_inputs_and_links(group, name): - node_tree = group - node_tree.name = name - links = node_tree.links - - # create group inputs - group_inputs = group.nodes.new('NodeGroupInput') - group_inputs.location = (-350,0) - - addInputInt(group, 'Technique', default=1, min=0, max=3) - group.inputs.new('NodeSocketColor', 'Diffuse') - group.inputs['Diffuse'].default_value = (0.8, 0.8, 0.8, 1.0) - group.inputs.new('NodeSocketColor', 'DiffuseTexture') - group.inputs['DiffuseTexture'].default_value = (0.8, 0.8, 0.8, 1.0) - group.inputs.new('NodeSocketFloat', 'DiffuseTextureAlpha') - group.inputs['DiffuseTextureAlpha'].default_value = 1.0 - addInputInt(group, 'AlphaTestEnable', max=1) - group.inputs.new('NodeSocketColor', 'NormalMap') - group.inputs.new('NodeSocketFloat', 'NormalMapStrength') - group.inputs.new('NodeSocketFloat', 'BumpScale') - group.inputs.new('NodeSocketColor', 'Ambient') - group.inputs['Ambient'].default_value = (0.8, 0.8, 0.8, 1.0) - group.inputs.new('NodeSocketColor', 'Specular') - group.inputs.new('NodeSocketFloat', 'SpecularExponent') - - # create group outputs - group_outputs = group.nodes.new('NodeGroupOutput') - group_outputs.location = (300,0) - group.outputs.new('NodeSocketShader', 'BSDF') - - alpha_pipeline = node_tree.nodes.new(type='ShaderNodeGroup') - alpha_pipeline.location = (-100, 0) - alpha_pipeline.node_tree = bpy.data.node_groups['AlphaPipeline'] - links.new(group_inputs.outputs['DiffuseTexture'], alpha_pipeline.inputs['Diffuse']) - links.new(group_inputs.outputs['DiffuseTextureAlpha'], alpha_pipeline.inputs['Alpha']) - links.new(group_inputs.outputs['AlphaTestEnable'], alpha_pipeline.inputs['DestBlend']) - - normal = create_normal_map_node(node_tree) - normal.location = (-100, -200) - links.new(group_inputs.outputs['NormalMap'], normal.inputs['Color']) - links.new(group_inputs.outputs['NormalMapStrength'], normal.inputs['Strength']) - - shader = create_specular_shader_node(node_tree) - shader.location = (100, 0) - shader.inputs['Emissive Color'].hide = True - - links.new(group_inputs.outputs['DiffuseTexture'], shader.inputs['Base Color']) - links.new(group_inputs.outputs['Specular'], shader.inputs['Specular']) - links.new(group_inputs.outputs['SpecularExponent'], shader.inputs['Roughness']) - links.new(alpha_pipeline.outputs['Alpha'], shader.inputs['Transparency']) - links.new(normal.outputs['Normal'], shader.inputs['Normal']) - links.new(shader.outputs['BSDF'], group_outputs.inputs['BSDF']) - - - @staticmethod - def register(): - group = bpy.data.node_groups.new(NormalMappedGroup.name, 'ShaderNodeTree') - NormalMappedGroup.create_inputs_and_links(group, NormalMappedGroup.name) + return NormalMappedGroup.apply_data(context, node_tree, instance, shader_mat, uv_layer) \ No newline at end of file diff --git a/io_mesh_w3d/common/node_groups/vertex_material.py b/io_mesh_w3d/common/node_groups/vertex_material.py index ad8dba40..e15287ec 100644 --- a/io_mesh_w3d/common/node_groups/vertex_material.py +++ b/io_mesh_w3d/common/node_groups/vertex_material.py @@ -43,10 +43,10 @@ def create(node_tree, name, vm_info, shader): return instance @staticmethod - def register(): - group = bpy.data.node_groups.new(VertexMaterialGroup.name, 'ShaderNodeTree') + def register(name): + group = bpy.data.node_groups.new(name, 'ShaderNodeTree') node_tree = group - node_tree.name = VertexMaterialGroup.name + node_tree.name = name links = node_tree.links # create group inputs diff --git a/io_mesh_w3d/common/utils/node_group_creator.py b/io_mesh_w3d/common/utils/node_group_creator.py index bdc9070d..d44801a2 100644 --- a/io_mesh_w3d/common/utils/node_group_creator.py +++ b/io_mesh_w3d/common/utils/node_group_creator.py @@ -10,14 +10,17 @@ class NodeGroupCreator(): @staticmethod - def create_node_group(path): - print(path) + def create(directory, file): + path = os.path.join(directory, file) + print('parsing: ' + path) root = find_root(None, path) if root is None: - print('None') return name = root.get('name') + if name in bpy.data.node_groups: + return + group = bpy.data.node_groups.new(name, 'ShaderNodeTree') node_tree = group links = node_tree.links @@ -25,7 +28,10 @@ def create_node_group(path): nodes = {} for xml_node in root: - if xml_node.tag == 'node': + if xml_node.tag == 'include': + file = xml_node.get('file') + NodeGroupCreator.create(directory, file) + elif xml_node.tag == 'node': type = xml_node.get('type') node = group.nodes.new(type) x = float(xml_node.get('X', 0.0)) @@ -40,7 +46,6 @@ def create_node_group(path): input_type = child_node.get('type') input_name = child_node.get('name') group.inputs.new(input_type, input_name) - print('created input: ' + input_name) #default = child_node.get('default') #if default is not None: @@ -73,7 +78,6 @@ def create_node_group(path): output_type = child_node.get('type') output_name = child_node.get('name') group.outputs.new(input_type, output_name) - print('created output: ' + output_name) if type == 'ShaderNodeMath': node.operation = xml_node.get('mode').upper() @@ -85,10 +89,21 @@ def create_node_group(path): # default = child_node.get('default') # node.inputs[int(id)] = int(default) + elif xml_node.tag == 'nodegroup': + nodegroup = node_tree.nodes.new(type='ShaderNodeGroup') + x = float(xml_node.get('X', 0.0)) + y = float(xml_node.get('Y', 0.0)) + nodegroup.location = (x, y) + nodegroup.node_tree = bpy.data.node_groups[xml_node.get('type')] + nodes[xml_node.get('name')] = nodegroup + elif xml_node.tag == 'link': from_data = xml_node.get('from').split('.') to_data = xml_node.get('to').split('.') + print(from_data) + print(to_data) + from_node = nodes[from_data[0]] to_node = nodes[to_data[0]] @@ -99,9 +114,6 @@ def create_node_group(path): if to_port.isdigit(): to_port = int(to_port) - print(from_data) - print(to_data) - if from_data[1] == 'inputs': from_port = from_node.inputs[from_port] else: @@ -116,12 +128,3 @@ def create_node_group(path): else: print('node type: ' + xml_node.tag + ' is not supported') - @staticmethod - def create(): - dirname = os.path.dirname(__file__) - directory = os.path.join(up(up(dirname)), 'node_group_templates') - - for file in os.listdir(directory): - if file.endswith(".xml"): - NodeGroupCreator.create_node_group(os.path.join(directory, file)) - diff --git a/io_mesh_w3d/node_group_templates/alpha_pipeline.xml b/io_mesh_w3d/node_group_templates/alpha_pipeline.xml index 166b23c8..2d1c8d31 100644 --- a/io_mesh_w3d/node_group_templates/alpha_pipeline.xml +++ b/io_mesh_w3d/node_group_templates/alpha_pipeline.xml @@ -1,5 +1,5 @@ - + diff --git a/io_mesh_w3d/node_group_templates/normal_mapped.xml b/io_mesh_w3d/node_group_templates/normal_mapped.xml new file mode 100644 index 00000000..884fed10 --- /dev/null +++ b/io_mesh_w3d/node_group_templates/normal_mapped.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 4e2174aa441f3d96e407a9bb723ede3220792718 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Sat, 4 Apr 2020 19:51:25 +0200 Subject: [PATCH 29/62] create normal_mapped completely from xml template --- .../common/node_groups/normal_mapped.py | 61 ------------------- io_mesh_w3d/common/node_groups/objects_gdi.py | 61 ------------------- io_mesh_w3d/common/utils/material_import.py | 47 +++++++++----- .../common/utils/node_group_creator.py | 11 ++++ .../node_group_templates/normal_mapped.xml | 14 +++-- 5 files changed, 53 insertions(+), 141 deletions(-) delete mode 100644 io_mesh_w3d/common/node_groups/normal_mapped.py delete mode 100644 io_mesh_w3d/common/node_groups/objects_gdi.py diff --git a/io_mesh_w3d/common/node_groups/normal_mapped.py b/io_mesh_w3d/common/node_groups/normal_mapped.py deleted file mode 100644 index 1dabfafd..00000000 --- a/io_mesh_w3d/common/node_groups/normal_mapped.py +++ /dev/null @@ -1,61 +0,0 @@ -# -# Written by Stephan Vedder and Michael Schnabel - -import bpy -from io_mesh_w3d.common.utils.helpers import * -from io_mesh_w3d.common.node_groups.helpers import * - - -class NormalMappedGroup(): - name = 'NormalMapped.fx' - - @staticmethod - def apply_data(context, node_tree, instance, shader_mat, uv_layer): - links = node_tree.links - - if shader_mat.header.technique is not None: - instance.inputs['Technique'].default_value = shader_mat.header.technique - - for prop in shader_mat.properties: - if prop.name in ['DiffuseTexture', 'Texture_0'] and prop.value != '': - texture_node = create_texture_node(node_tree, find_texture(context, prop.value)) - texture_node.location = (-550, 600) - links.new(texture_node.outputs['Color'], instance.inputs['DiffuseTexture']) - links.new(texture_node.outputs['Alpha'], instance.inputs['DiffuseTextureAlpha']) - uv_node = create_uv_map_node(node_tree) - uv_node.uv_map = uv_layer - uv_node.location = (-750, 600) - links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) - - elif prop.name == 'NormalMap' and prop.value != '': - texture_node = create_texture_node(node_tree, find_texture(context, prop.value)) - texture_node.location = (-550, -300) - links.new(texture_node.outputs['Color'], instance.inputs['NormalMap']) - links.new(texture_node.outputs['Alpha'], instance.inputs['NormalMapStrength']) - uv_node = create_uv_map_node(node_tree) - uv_node.uv_map = uv_layer - uv_node.location = (-750, -300) - links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) - - elif prop.name in ['DiffuseColor', 'ColorDiffuse']: - instance.inputs['Diffuse'].default_value = prop.to_rgba() - elif prop.name in ['AmbientColor', 'ColorAmbient']: - instance.inputs['Ambient'].default_value = prop.to_rgba() - elif prop.name in ['SpecularColor', 'ColorSpecular']: - instance.inputs['Specular'].default_value = prop.to_rgba() - elif prop.name in ['SpecularExponent', 'BumpScale', 'AlphaTestEnable']: - instance.inputs[prop.name].default_value = prop.value - else: - context.warning(prop.name + ' -> is not a valid input of:' + NormalMappedGroup.name) - - return instance - - @staticmethod - def create(context, node_tree, shader_mat, uv_layer): - instance = node_tree.nodes.new(type='ShaderNodeGroup') - instance.node_tree = bpy.data.node_groups[NormalMappedGroup.name] - instance.label = NormalMappedGroup.name - instance.location = (0, 300) - instance.width = 300 - - return NormalMappedGroup.apply_data(context, node_tree, instance, shader_mat, uv_layer) \ No newline at end of file diff --git a/io_mesh_w3d/common/node_groups/objects_gdi.py b/io_mesh_w3d/common/node_groups/objects_gdi.py deleted file mode 100644 index 27a952e8..00000000 --- a/io_mesh_w3d/common/node_groups/objects_gdi.py +++ /dev/null @@ -1,61 +0,0 @@ -# -# Written by Stephan Vedder and Michael Schnabel - -import bpy -from io_mesh_w3d.common.node_groups.normal_mapped import * - - -class ObjectsGDIGroup(NormalMappedGroup): - name = 'ObjectsGDI.fx' - - @staticmethod - def create(context, node_tree, shader_mat, uv_layer): - instance = node_tree.nodes.new(type='ShaderNodeGroup') - instance.node_tree = bpy.data.node_groups[ObjectsGDIGroup.name] - instance.label = ObjectsGDIGroup.name - instance.location = (0, 300) - instance.width = 300 - - instance = NormalMappedGroup.apply_data(context, node_tree, instance, shader_mat, uv_layer) - links = node_tree.links - - for prop in shader_mat.properties: - if prop.name == 'RecolorTexture' and prop.value != '': - texture_node = create_texture_node(node_tree, find_texture(context, prop.value)) - texture_node.location = (-550, 600) - links.new(texture_node.outputs['Color'], instance.inputs['RecolorTexture']) - links.new(texture_node.outputs['Alpha'], instance.inputs['RecolorTextureAlpha']) - uv_node = create_uv_map_node(node_tree) - uv_node.uv_map = uv_layer - uv_node.location = (-750, 600) - links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) - if prop.name == 'EnvironmentTexture' and prop.value != '': - texture_node = create_texture_node(node_tree, find_texture(context, prop.value)) - texture_node.location = (-550, 600) - links.new(texture_node.outputs['Color'], instance.inputs['EnvironmentTexture']) - links.new(texture_node.outputs['Alpha'], instance.inputs['EnvironmentTextureAlpha']) - uv_node = create_uv_map_node(node_tree) - uv_node.uv_map = uv_layer - uv_node.location = (-750, 600) - links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) - elif prop.name in ['RecolorTextureAlpha', 'EnvMult']: - instance.inputs[prop.name].default_value = prop.value - else: - context.warning(prop.name + ' -> is not a valid input of: ' + ObjectsGDIGroup.name) - - return instance - - @staticmethod - def register(): - group = bpy.data.node_groups.new(ObjectsGDIGroup.name, 'ShaderNodeTree') - NormalMappedGroup.create_inputs_and_links(group, ObjectsGDIGroup.name) - - group.inputs.new('NodeSocketColor', 'RecolorTexture') - group.inputs.new('NodeSocketFloat', 'RecolorTextureAlpha') - group.inputs.new('NodeSocketColor', 'EnvironmentTexture') - group.inputs.new('NodeSocketColor', 'EnvironmentTextureAlpha') - group.inputs.new('NodeSocketFloat', 'EnvMult') - - -class ObjectsAlienGroup(ObjectsGDIGroup): - name = 'ObjectsAlien.fx' \ No newline at end of file diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index 22a351a8..df60e962 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -6,11 +6,10 @@ from bpy_extras import node_shader_utils from io_mesh_w3d.common.node_groups.vertex_material import * -from io_mesh_w3d.common.node_groups.normal_mapped import * -from io_mesh_w3d.common.node_groups.objects_gdi import * from io_mesh_w3d.common.node_groups.helpers import * from io_mesh_w3d.common.utils.helpers import * from io_mesh_w3d.w3d.structs.mesh_structs.vertex_material import * +from io_mesh_w3d.common.structs.mesh_structs.shader_material import * def get_or_create_uv_layer(mesh, b_mesh, triangles, tx_coords): @@ -149,12 +148,6 @@ def create_shader_material(context, mesh, b_mesh, triangles, shader_mat, tx_coor # mesh.materials.append(bpy.data.materials[mat_name]) # return - if mat_name not in [NormalMappedGroup.name, - ObjectsGDIGroup.name, - ObjectsAlienGroup.name]: - context.error('no NodeGroup found for: ' + mat_name) - return - material = bpy.data.materials.new(mat_name) mesh.materials.append(material) material.use_nodes = True @@ -168,12 +161,38 @@ def create_shader_material(context, mesh, b_mesh, triangles, shader_mat, tx_coor uv_layer = get_or_create_uv_layer(mesh, b_mesh, triangles, tx_coords) - if mat_name == NormalMappedGroup.name: - instance = NormalMappedGroup.create(context, node_tree, shader_mat, uv_layer) - elif mat_name == ObjectsGDIGroup.name: - instance = ObjectsGDIGroup.create(context, node_tree, shader_mat, uv_layer) - elif mat_name == ObjectsAlienGroup.name: - instance = ObjectsAlienGroup.create(context, node_tree, shader_mat, uv_layer) + instance = node_tree.nodes.new(type='ShaderNodeGroup') + instance.node_tree = bpy.data.node_groups[mat_name] + instance.label = mat_name + instance.location = (0, 300) + instance.width = 200 + + links = node_tree.links + + if shader_mat.header.technique is not None: + instance.inputs['Technique'].default_value = shader_mat.header.technique + + uv_node = None + y = 300 + + for prop in shader_mat.properties: + if prop.type == STRING_PROPERTY and prop.value != '': + texture_node = create_texture_node(node_tree, find_texture(context, prop.value)) + texture_node.location = (-350, y) + y -= 300 + links.new(texture_node.outputs['Color'], instance.inputs[prop.name]) + index = instance.inputs.keys().index(prop.name) + links.new(texture_node.outputs['Alpha'], instance.inputs[index + 1]) + + if uv_node is None: + uv_node = create_uv_map_node(node_tree) + uv_node.uv_map = uv_layer + uv_node.location = (-600, 300) + links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) + elif prop.type == VEC4_PROPERTY: + instance.inputs[prop.name].default_value = prop.to_rgba() + else: + instance.inputs[prop.name].default_value = prop.value output = node_tree.nodes.get('Material Output') links.new(instance.outputs['BSDF'], output.inputs['Surface']) diff --git a/io_mesh_w3d/common/utils/node_group_creator.py b/io_mesh_w3d/common/utils/node_group_creator.py index d44801a2..6738c0e5 100644 --- a/io_mesh_w3d/common/utils/node_group_creator.py +++ b/io_mesh_w3d/common/utils/node_group_creator.py @@ -39,6 +39,17 @@ def create(directory, file): node.location = (x, y) nodes[xml_node.get('name')] = node + for child_node in xml_node: + if child_node.tag != 'hide': + continue + id = child_node.get('id') + port_type = child_node.get('type') + + if port_type == 'input': + node.inputs[id].hide = True + else: + node.outputs[id].hide = True + if type == 'NodeGroupInput': for child_node in xml_node: if child_node.tag != 'input': diff --git a/io_mesh_w3d/node_group_templates/normal_mapped.xml b/io_mesh_w3d/node_group_templates/normal_mapped.xml index 884fed10..bfa5cd24 100644 --- a/io_mesh_w3d/node_group_templates/normal_mapped.xml +++ b/io_mesh_w3d/node_group_templates/normal_mapped.xml @@ -3,15 +3,15 @@ - + - - + + @@ -25,11 +25,15 @@ - + + + + + - + From fda53a86c13dce206d8d84c20a6e96537734c990 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Sat, 4 Apr 2020 20:47:49 +0200 Subject: [PATCH 30/62] got objectsGDI working with parenting, added muzzleflash.fx --- .../common/utils/node_group_creator.py | 35 +++++++++++-------- .../node_group_templates/MuzzleFlash.xml | 34 ++++++++++++++++++ .../{normal_mapped.xml => NormalMapped.xml} | 2 +- .../node_group_templates/ObjectsGDI.xml | 9 +++++ 4 files changed, 64 insertions(+), 16 deletions(-) create mode 100644 io_mesh_w3d/node_group_templates/MuzzleFlash.xml rename io_mesh_w3d/node_group_templates/{normal_mapped.xml => NormalMapped.xml} (96%) create mode 100644 io_mesh_w3d/node_group_templates/ObjectsGDI.xml diff --git a/io_mesh_w3d/common/utils/node_group_creator.py b/io_mesh_w3d/common/utils/node_group_creator.py index 6738c0e5..5dcfab1c 100644 --- a/io_mesh_w3d/common/utils/node_group_creator.py +++ b/io_mesh_w3d/common/utils/node_group_creator.py @@ -10,7 +10,7 @@ class NodeGroupCreator(): @staticmethod - def create(directory, file): + def create(directory, file, node_tree=None): path = os.path.join(directory, file) print('parsing: ' + path) root = find_root(None, path) @@ -18,22 +18,27 @@ def create(directory, file): return name = root.get('name') - if name in bpy.data.node_groups: + if name in bpy.data.node_groups and node_tree is None: + print('is none') return - group = bpy.data.node_groups.new(name, 'ShaderNodeTree') - node_tree = group - links = node_tree.links + if node_tree is None: + print('new node tree: ' + name) + node_tree = bpy.data.node_groups.new(name, 'ShaderNodeTree') + links = node_tree.links nodes = {} for xml_node in root: if xml_node.tag == 'include': file = xml_node.get('file') NodeGroupCreator.create(directory, file) + elif xml_node.tag == 'parent': + parent = xml_node.get('file') + nodes = NodeGroupCreator.create(directory, parent, node_tree) elif xml_node.tag == 'node': type = xml_node.get('type') - node = group.nodes.new(type) + node = node_tree.nodes.new(type) x = float(xml_node.get('X', 0.0)) y = float(xml_node.get('Y', 0.0)) node.location = (x, y) @@ -56,7 +61,7 @@ def create(directory, file): continue input_type = child_node.get('type') input_name = child_node.get('name') - group.inputs.new(input_type, input_name) + node_tree.inputs.new(input_type, input_name) #default = child_node.get('default') #if default is not None: @@ -64,7 +69,7 @@ def create(directory, file): # default = float(default) # elif input_type == 'NodeSocketInt': # default = int(default) - # group.inputs[input_name].default_value = default + # node_tree.inputs[input_name].default_value = default #min = child_node.get('min') #if min is not None: @@ -72,7 +77,7 @@ def create(directory, file): # min = float(min) # elif input_type == 'NodeSocketInt': # min = int(min) - # group.inputs[input_name].min_value = min + # node_tree.inputs[input_name].min_value = min #max = child_node.get('max') #if max is not None: @@ -80,7 +85,7 @@ def create(directory, file): # max = float(max) # elif input_type == 'NodeSocketInt': # max = int(max) - # group.inputs[input_name].max_value = max + # node_tree.inputs[input_name].max_value = max elif type == 'NodeGroupOutput': for child_node in xml_node: @@ -88,7 +93,7 @@ def create(directory, file): continue output_type = child_node.get('type') output_name = child_node.get('name') - group.outputs.new(input_type, output_name) + node_tree.outputs.new(input_type, output_name) if type == 'ShaderNodeMath': node.operation = xml_node.get('mode').upper() @@ -98,7 +103,7 @@ def create(directory, file): # id = child_node.get('id') # TODO: support multiple input types # default = child_node.get('default') - # node.inputs[int(id)] = int(default) + # node_tree.inputs[int(id)] = int(default) elif xml_node.tag == 'nodegroup': nodegroup = node_tree.nodes.new(type='ShaderNodeGroup') @@ -112,8 +117,8 @@ def create(directory, file): from_data = xml_node.get('from').split('.') to_data = xml_node.get('to').split('.') - print(from_data) - print(to_data) + #print(from_data) + #print(to_data) from_node = nodes[from_data[0]] to_node = nodes[to_data[0]] @@ -138,4 +143,4 @@ def create(directory, file): links.new(from_port, to_port) else: print('node type: ' + xml_node.tag + ' is not supported') - + return nodes diff --git a/io_mesh_w3d/node_group_templates/MuzzleFlash.xml b/io_mesh_w3d/node_group_templates/MuzzleFlash.xml new file mode 100644 index 00000000..93fcc636 --- /dev/null +++ b/io_mesh_w3d/node_group_templates/MuzzleFlash.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/io_mesh_w3d/node_group_templates/normal_mapped.xml b/io_mesh_w3d/node_group_templates/NormalMapped.xml similarity index 96% rename from io_mesh_w3d/node_group_templates/normal_mapped.xml rename to io_mesh_w3d/node_group_templates/NormalMapped.xml index bfa5cd24..be992c75 100644 --- a/io_mesh_w3d/node_group_templates/normal_mapped.xml +++ b/io_mesh_w3d/node_group_templates/NormalMapped.xml @@ -4,7 +4,7 @@ - + diff --git a/io_mesh_w3d/node_group_templates/ObjectsGDI.xml b/io_mesh_w3d/node_group_templates/ObjectsGDI.xml new file mode 100644 index 00000000..f80d6eae --- /dev/null +++ b/io_mesh_w3d/node_group_templates/ObjectsGDI.xml @@ -0,0 +1,9 @@ + + + + + + + + + From a452f59fecfae516ac2efd13516c58eafccc5d3c Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Sat, 4 Apr 2020 21:32:02 +0200 Subject: [PATCH 31/62] small fixes --- io_mesh_w3d/common/utils/material_import.py | 9 ++++++--- io_mesh_w3d/common/utils/node_group_creator.py | 7 ------- io_mesh_w3d/node_group_templates/MuzzleFlash.xml | 4 ++-- io_mesh_w3d/node_group_templates/NormalMapped.xml | 10 +++++----- io_mesh_w3d/node_group_templates/ObjectsAlien.xml | 8 ++++++++ io_mesh_w3d/node_group_templates/ObjectsGDI.xml | 1 + 6 files changed, 22 insertions(+), 17 deletions(-) create mode 100644 io_mesh_w3d/node_group_templates/ObjectsAlien.xml diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index df60e962..e65ad7e8 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -113,8 +113,11 @@ def create_vertex_material(context, mesh, b_mesh, triangles, vert_mat, shader, t links = node_tree.links node_tree.nodes.remove(node_tree.nodes.get('Principled BSDF')) - + instance = VertexMaterialGroup.create(node_tree, vert_mat.vm_name, vert_mat.vm_info, shader) + instance.label = vert_mat.vm_name + instance.location = (0, 300) + instance.width = 200 output = node_tree.nodes.get('Material Output') links.new(instance.outputs['BSDF'], output.inputs['Surface']) @@ -123,7 +126,7 @@ def create_vertex_material(context, mesh, b_mesh, triangles, vert_mat, shader, t texture = find_texture(context, texture_struct.file, texture_struct.id) texture_node = create_texture_node(node_tree, texture) - texture_node.location = (-250, 0) + texture_node.location = (-350, 300) links.new(texture_node.outputs['Color'], instance.inputs['Diffuse']) links.new(texture_node.outputs['Alpha'], instance.inputs['DiffuseAlpha']) @@ -131,7 +134,7 @@ def create_vertex_material(context, mesh, b_mesh, triangles, vert_mat, shader, t uv_node = create_uv_map_node(node_tree) uv_node.uv_map = uv_layer - uv_node.location = (-450, 0) + uv_node.location = (-550, 300) links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) diff --git a/io_mesh_w3d/common/utils/node_group_creator.py b/io_mesh_w3d/common/utils/node_group_creator.py index 5dcfab1c..2515ee06 100644 --- a/io_mesh_w3d/common/utils/node_group_creator.py +++ b/io_mesh_w3d/common/utils/node_group_creator.py @@ -3,7 +3,6 @@ import os import bpy -from os.path import dirname as up from io_mesh_w3d.common.io_xml import * from io_mesh_w3d.common.node_groups.helpers import * @@ -12,18 +11,15 @@ class NodeGroupCreator(): @staticmethod def create(directory, file, node_tree=None): path = os.path.join(directory, file) - print('parsing: ' + path) root = find_root(None, path) if root is None: return name = root.get('name') if name in bpy.data.node_groups and node_tree is None: - print('is none') return if node_tree is None: - print('new node tree: ' + name) node_tree = bpy.data.node_groups.new(name, 'ShaderNodeTree') links = node_tree.links @@ -117,9 +113,6 @@ def create(directory, file, node_tree=None): from_data = xml_node.get('from').split('.') to_data = xml_node.get('to').split('.') - #print(from_data) - #print(to_data) - from_node = nodes[from_data[0]] to_node = nodes[to_data[0]] diff --git a/io_mesh_w3d/node_group_templates/MuzzleFlash.xml b/io_mesh_w3d/node_group_templates/MuzzleFlash.xml index 93fcc636..c49de3aa 100644 --- a/io_mesh_w3d/node_group_templates/MuzzleFlash.xml +++ b/io_mesh_w3d/node_group_templates/MuzzleFlash.xml @@ -23,10 +23,10 @@ - + - + diff --git a/io_mesh_w3d/node_group_templates/NormalMapped.xml b/io_mesh_w3d/node_group_templates/NormalMapped.xml index be992c75..864f1b51 100644 --- a/io_mesh_w3d/node_group_templates/NormalMapped.xml +++ b/io_mesh_w3d/node_group_templates/NormalMapped.xml @@ -14,16 +14,16 @@ - + - + - + @@ -31,13 +31,13 @@ - + - + diff --git a/io_mesh_w3d/node_group_templates/ObjectsAlien.xml b/io_mesh_w3d/node_group_templates/ObjectsAlien.xml new file mode 100644 index 00000000..c50bac2e --- /dev/null +++ b/io_mesh_w3d/node_group_templates/ObjectsAlien.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/io_mesh_w3d/node_group_templates/ObjectsGDI.xml b/io_mesh_w3d/node_group_templates/ObjectsGDI.xml index f80d6eae..df12773b 100644 --- a/io_mesh_w3d/node_group_templates/ObjectsGDI.xml +++ b/io_mesh_w3d/node_group_templates/ObjectsGDI.xml @@ -4,6 +4,7 @@ + From 36552ae16d522132bb1c933872499ec38f45a774 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Sat, 4 Apr 2020 23:25:11 +0200 Subject: [PATCH 32/62] added more shader templates --- io_mesh_w3d/common/utils/material_import.py | 6 +-- .../node_group_templates/DefaultW3D.xml | 54 +++++++++++++++++++ .../node_group_templates/ObjectsGDI.xml | 1 + .../node_group_templates/ObjectsNOD.xml | 13 +++++ 4 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 io_mesh_w3d/node_group_templates/DefaultW3D.xml create mode 100644 io_mesh_w3d/node_group_templates/ObjectsNOD.xml diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index e65ad7e8..6896c782 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -147,9 +147,9 @@ def create_shader_material(context, mesh, b_mesh, triangles, shader_mat, tx_coor mat_name = shader_mat.header.type_name # TODO: verify that - #if mat_name in bpy.data.materials: - # mesh.materials.append(bpy.data.materials[mat_name]) - # return + if mat_name in bpy.data.materials: + mesh.materials.append(bpy.data.materials[mat_name]) + return material = bpy.data.materials.new(mat_name) mesh.materials.append(material) diff --git a/io_mesh_w3d/node_group_templates/DefaultW3D.xml b/io_mesh_w3d/node_group_templates/DefaultW3D.xml new file mode 100644 index 00000000..25b919f6 --- /dev/null +++ b/io_mesh_w3d/node_group_templates/DefaultW3D.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/io_mesh_w3d/node_group_templates/ObjectsGDI.xml b/io_mesh_w3d/node_group_templates/ObjectsGDI.xml index df12773b..d3a16a23 100644 --- a/io_mesh_w3d/node_group_templates/ObjectsGDI.xml +++ b/io_mesh_w3d/node_group_templates/ObjectsGDI.xml @@ -3,6 +3,7 @@ + diff --git a/io_mesh_w3d/node_group_templates/ObjectsNOD.xml b/io_mesh_w3d/node_group_templates/ObjectsNOD.xml new file mode 100644 index 00000000..0ee96077 --- /dev/null +++ b/io_mesh_w3d/node_group_templates/ObjectsNOD.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + From 827097e7df948b0477eed0ee91ded26295e55678 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Sun, 5 Apr 2020 11:47:06 +0200 Subject: [PATCH 33/62] added infantry and basicw3d fx shaders --- io_mesh_w3d/node_group_templates/BasicW3D.xml | 42 ++++++++++++++++++ .../node_group_templates/DefaultW3D.xml | 3 ++ io_mesh_w3d/node_group_templates/Infantry.xml | 44 +++++++++++++++++++ 3 files changed, 89 insertions(+) create mode 100644 io_mesh_w3d/node_group_templates/BasicW3D.xml create mode 100644 io_mesh_w3d/node_group_templates/Infantry.xml diff --git a/io_mesh_w3d/node_group_templates/BasicW3D.xml b/io_mesh_w3d/node_group_templates/BasicW3D.xml new file mode 100644 index 00000000..f2c2c3f8 --- /dev/null +++ b/io_mesh_w3d/node_group_templates/BasicW3D.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/io_mesh_w3d/node_group_templates/DefaultW3D.xml b/io_mesh_w3d/node_group_templates/DefaultW3D.xml index 25b919f6..92f8e9c4 100644 --- a/io_mesh_w3d/node_group_templates/DefaultW3D.xml +++ b/io_mesh_w3d/node_group_templates/DefaultW3D.xml @@ -18,6 +18,9 @@ + + + diff --git a/io_mesh_w3d/node_group_templates/Infantry.xml b/io_mesh_w3d/node_group_templates/Infantry.xml new file mode 100644 index 00000000..a26d534c --- /dev/null +++ b/io_mesh_w3d/node_group_templates/Infantry.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 28bb6ee2c8aa1489e549ea9d4f07666072cfae60 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Sun, 5 Apr 2020 13:08:12 +0200 Subject: [PATCH 34/62] code refactoring and support preset values --- io_mesh_w3d/__init__.py | 2 +- .../common/utils/node_group_creator.py | 192 ++++++++++-------- 2 files changed, 109 insertions(+), 85 deletions(-) diff --git a/io_mesh_w3d/__init__.py b/io_mesh_w3d/__init__.py index 46ea4e47..4fce4f38 100644 --- a/io_mesh_w3d/__init__.py +++ b/io_mesh_w3d/__init__.py @@ -299,7 +299,7 @@ def register_node_groups(): for file in os.listdir(directory): if not file.endswith(".xml"): continue - NodeGroupCreator.create(directory, file) + NodeGroupCreator().create(directory, file) from io_mesh_w3d.common.node_groups.vertex_material import VertexMaterialGroup, PrelitUnlitGroup, PrelitVertexGroup, PrelitLightmapMultiPassGroup, PrelitLightmapMultiTextureGroup VertexMaterialGroup.register(VertexMaterialGroup.name) diff --git a/io_mesh_w3d/common/utils/node_group_creator.py b/io_mesh_w3d/common/utils/node_group_creator.py index 2515ee06..edf35499 100644 --- a/io_mesh_w3d/common/utils/node_group_creator.py +++ b/io_mesh_w3d/common/utils/node_group_creator.py @@ -3,13 +3,88 @@ import os import bpy +from mathutils import Vector from io_mesh_w3d.common.io_xml import * from io_mesh_w3d.common.node_groups.helpers import * class NodeGroupCreator(): - @staticmethod - def create(directory, file, node_tree=None): + def process_input_hides(self, xml_node, node): + for child_node in xml_node: + if child_node.tag != 'hide': + continue + id = child_node.get('id') + port_type = child_node.get('type') + + if port_type == 'input': + node.inputs[id].hide = True + else: + node.outputs[id].hide = True + + + def process_default_value(self, node_tree, input, type, default): + if default is None: + return + if type == 'NodeSocketFloat': + default = float(default) + elif type == 'NodeSocketInt': + default = int(default) + elif type == 'NodeSocketBool': + default = int(default) + elif type == 'NodeSocketColor': + values = default.split(',') + default = Vector((float(values[0]), float(values[1]), float(values[2]), float(values[3]))) + node_tree.inputs[input].default_value = default + + + def process_min_value(self, node_tree, input, type, min): + if min is None: + return + if type == 'NodeSocketFloat': + min = float(min) + elif type == 'NodeSocketInt': + min = int(min) + node_tree.inputs[input].min_value = min + + + def process_max_value(self, node_tree, input, type, max): + if max is None: + return + if type == 'NodeSocketFloat': + max = float(max) + elif type == 'NodeSocketInt': + max = int(max) + node_tree.inputs[input].max_value = max + + def process_presets(self, node_tree, xml_node, name=None, type=None): + if type is None: + type = xml_node.get('type') + if name is None: + name = xml_node.get('name', xml_node.get('id')) + + self.process_default_value(node_tree, name, type, xml_node.get('default')) + self.process_min_value(node_tree, name, type, xml_node.get('min')) + self.process_max_value(node_tree, name, type, xml_node.get('max')) + + + def create_input_node(self, node_tree, xml_node, node): + for child_node in xml_node: + if child_node.tag != 'input': + continue + type = child_node.get('type') + name = child_node.get('name') + node_tree.inputs.new(type, name) + self.process_presets(node_tree, child_node, name, type) + + + def create_output_node(self, node_tree, xml_node, node): + for child_node in xml_node: + if child_node.tag != 'output': + continue + node_tree.outputs.new(child_node.get('type'), child_node.get('name')) + + + def create(self, directory, file, node_tree=None): path = os.path.join(directory, file) root = find_root(None, path) if root is None: @@ -26,114 +101,63 @@ def create(directory, file, node_tree=None): nodes = {} for xml_node in root: + location = (float(xml_node.get('X', 0.0)), float(xml_node.get('Y', 0.0))) + if xml_node.tag == 'include': file = xml_node.get('file') - NodeGroupCreator.create(directory, file) + NodeGroupCreator().create(directory, file) + elif xml_node.tag == 'parent': parent = xml_node.get('file') - nodes = NodeGroupCreator.create(directory, parent, node_tree) + nodes = NodeGroupCreator().create(directory, parent, node_tree) + elif xml_node.tag == 'node': type = xml_node.get('type') node = node_tree.nodes.new(type) - x = float(xml_node.get('X', 0.0)) - y = float(xml_node.get('Y', 0.0)) - node.location = (x, y) - nodes[xml_node.get('name')] = node - for child_node in xml_node: - if child_node.tag != 'hide': - continue - id = child_node.get('id') - port_type = child_node.get('type') + node.location = location + nodes[xml_node.get('name')] = node - if port_type == 'input': - node.inputs[id].hide = True - else: - node.outputs[id].hide = True + self.process_input_hides(xml_node, node) if type == 'NodeGroupInput': - for child_node in xml_node: - if child_node.tag != 'input': - continue - input_type = child_node.get('type') - input_name = child_node.get('name') - node_tree.inputs.new(input_type, input_name) - - #default = child_node.get('default') - #if default is not None: - # if input_type == 'NodeSocketFloat': - # default = float(default) - # elif input_type == 'NodeSocketInt': - # default = int(default) - # node_tree.inputs[input_name].default_value = default - - #min = child_node.get('min') - #if min is not None: - # if input_type == 'NodeSocketFloat': - # min = float(min) - # elif input_type == 'NodeSocketInt': - # min = int(min) - # node_tree.inputs[input_name].min_value = min - - #max = child_node.get('max') - #if max is not None: - # if input_type == 'NodeSocketFloat': - # max = float(max) - # elif input_type == 'NodeSocketInt': - # max = int(max) - # node_tree.inputs[input_name].max_value = max - + self.create_input_node(node_tree, xml_node, node) elif type == 'NodeGroupOutput': - for child_node in xml_node: - if child_node.tag != 'output': - continue - output_type = child_node.get('type') - output_name = child_node.get('name') - node_tree.outputs.new(input_type, output_name) - - if type == 'ShaderNodeMath': + self.create_output_node(node_tree, xml_node, node) + elif type == 'ShaderNodeMath': node.operation = xml_node.get('mode').upper() - #for child_node in xml_node: - # if child_node.tag != 'input': - # continue - # id = child_node.get('id') - # TODO: support multiple input types - # default = child_node.get('default') - # node_tree.inputs[int(id)] = int(default) + self.process_presets(node_tree, xml_node) + elif type in ['ShaderNodeEeveeSpecular', 'ShaderNodeNormalMap', 'ShaderNodeSeparateHSV']: + continue + else: + print('shader node type: ' + type + ' is not yet supported') elif xml_node.tag == 'nodegroup': nodegroup = node_tree.nodes.new(type='ShaderNodeGroup') - x = float(xml_node.get('X', 0.0)) - y = float(xml_node.get('Y', 0.0)) - nodegroup.location = (x, y) + nodegroup.location = location nodegroup.node_tree = bpy.data.node_groups[xml_node.get('type')] nodes[xml_node.get('name')] = nodegroup elif xml_node.tag == 'link': - from_data = xml_node.get('from').split('.') - to_data = xml_node.get('to').split('.') - - from_node = nodes[from_data[0]] - to_node = nodes[to_data[0]] + (from_node, from_port, from_input) = xml_node.get('from').split('.') + (to_node, to_port, to_input) = xml_node.get('to').split('.') - from_port = from_data[2] - if from_port.isdigit(): - from_port = int(from_port) - to_port = to_data[2] - if to_port.isdigit(): - to_port = int(to_port) + if from_input.isdigit(): + from_input = int(from_input) + if to_input.isdigit(): + to_input = int(to_input) - if from_data[1] == 'inputs': - from_port = from_node.inputs[from_port] + if from_port == 'inputs': + from_ref = nodes[from_node].inputs[from_input] else: - from_port = from_node.outputs[from_port] + from_ref = nodes[from_node].outputs[from_input] - if to_data[1] == 'inputs': - to_port = to_node.inputs[to_port] + if to_port == 'inputs': + to_ref = nodes[to_node].inputs[to_input] else: - to_port = to_node.outputs[to_port] + to_ref = nodes[to_node].outputs[to_input] - links.new(from_port, to_port) + links.new(from_ref, to_ref) else: print('node type: ' + xml_node.tag + ' is not supported') return nodes From 9f6d8aa91adb1a32f79d852331b71ab0fbd33973 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Mon, 6 Apr 2020 08:40:22 +0200 Subject: [PATCH 35/62] more work on material stuff --- .idea/OpenSAGE.BlenderPlugin.iml | 2 +- .idea/misc.xml | 2 +- io_mesh_w3d/__init__.py | 3 +- io_mesh_w3d/common/node_groups/helpers.py | 83 ------------ .../common/node_groups/vertex_material.py | 3 +- io_mesh_w3d/common/utils/material_import.py | 56 ++++---- .../common/utils/node_group_creator.py | 2 - .../node_group_templates/alpha_pipeline.xml | 4 +- tests/common/cases/test_custom_properties.py | 122 ------------------ tests/utils.py | 5 +- 10 files changed, 43 insertions(+), 239 deletions(-) diff --git a/.idea/OpenSAGE.BlenderPlugin.iml b/.idea/OpenSAGE.BlenderPlugin.iml index 5559130d..3cf11d78 100644 --- a/.idea/OpenSAGE.BlenderPlugin.iml +++ b/.idea/OpenSAGE.BlenderPlugin.iml @@ -2,7 +2,7 @@ - + diff --git a/.idea/misc.xml b/.idea/misc.xml index 24cdd306..bb8db66f 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/io_mesh_w3d/__init__.py b/io_mesh_w3d/__init__.py index 4fce4f38..4b236dee 100644 --- a/io_mesh_w3d/__init__.py +++ b/io_mesh_w3d/__init__.py @@ -281,7 +281,6 @@ def draw(self, context): col.prop(mat, 'vm_args_1') - CLASSES = ( ExportW3D, ImportW3D, @@ -290,7 +289,6 @@ def draw(self, context): MATERIAL_PROPERTIES_PANEL_PT_w3d ) - def register_node_groups(): from io_mesh_w3d.common.utils.node_group_creator import NodeGroupCreator dirname = os.path.dirname(__file__) @@ -316,6 +314,7 @@ def register(): bpy.types.TOPBAR_MT_file_export.append(menu_func_export) # workaround to register the node group when the addon is active + # since bpy.data is not yet accessible import time from threading import Timer diff --git a/io_mesh_w3d/common/node_groups/helpers.py b/io_mesh_w3d/common/node_groups/helpers.py index b0cea983..6a7b5f64 100644 --- a/io_mesh_w3d/common/node_groups/helpers.py +++ b/io_mesh_w3d/common/node_groups/helpers.py @@ -1,12 +1,6 @@ # # Written by Stephan Vedder and Michael Schnabel - - #node.color = (1, 0.5, 0) - #node.use_custom_color = True - #node.name = 'Test' - #node.label - def addInputInt(group, name, default=0, min=0, max=255): group.inputs.new('NodeSocketInt', name) group.inputs[name].default_value = default @@ -14,83 +8,6 @@ def addInputInt(group, name, default=0, min=0, max=255): group.inputs[name].max_value = max -def create_specular_shader_node(node_tree): - # inputs: Base Color, Specular, Roughness, Emissive Color, Transparency, - # Normal, Clear Coat, Clear Coat Radius, Clear Coat Normal, Ambient Occlusion - # outputs: BSDF - - node = node_tree.nodes.new('ShaderNodeEeveeSpecular') - node.label = 'Shader' - # hide unused inputs - node.inputs['Clear Coat'].hide = True - node.inputs['Clear Coat Roughness'].hide = True - node.inputs['Clear Coat Normal'].hide = True - node.inputs['Ambient Occlusion'].hide = True - return node - -def create_texture_node(node_tree, texture): - # inputs: Vector - # outputs: Color, Alpha - - node = node_tree.nodes.new('ShaderNodeTexImage') - #node.color_mapping - #node.extension # interpolation past bounds - node.image = texture - #node.image_user - #node.interpolation - #node.projection - #node.projection_blend - #node.texture_mapping - return node - -def create_uv_map_node(node_tree): - # outputs: UV - - node = node_tree.nodes.new('ShaderNodeUVMap') - #node.uv_map = 'uvmapname' - return node - -def create_math_node(node_tree, mode='SUBTRACT'): - # inputs: Value, Value - # outputs: Value - - node = node_tree.nodes.new('ShaderNodeMath') - node.operation = mode - #node.clamp = False - return node - -def create_rgb_mix_node(node_tree): - # inputs: Fac, Color1, Color2 - # outputs: Color - - node = node_tree.nodes.new('ShaderNodeMixRGB') - #node.blend_type - #node.use_alpha - #node.use_clamp - return node - -def create_normal_map_node(node_tree): - # inputs: Strength, Color - # outputs: Normal - - node = node_tree.nodes.new('ShaderNodeNormalMap') - node.space = 'TANGENT' - #node.uv_map = 'uvmapname' - return node - -def create_seperate_hsv_node(node_tree): - # inputs: Color - # outputs: H, S, V - - node = node_tree.nodes.new('ShaderNodeSeparateHSV') - return node - -def create_rgb_node(node_tree): - # outputs: Color - - node = node_tree.nodes.new('ShaderNodeRGB') - return node - def get_connected_nodes(links, node, input, types=[]): nodes = [] for link in links: diff --git a/io_mesh_w3d/common/node_groups/vertex_material.py b/io_mesh_w3d/common/node_groups/vertex_material.py index e15287ec..22d2b4f7 100644 --- a/io_mesh_w3d/common/node_groups/vertex_material.py +++ b/io_mesh_w3d/common/node_groups/vertex_material.py @@ -95,7 +95,8 @@ def register(name): links.new(group_inputs.outputs['DiffuseAlpha'], alpha_pipeline.inputs['Alpha']) links.new(group_inputs.outputs['DestBlend'], alpha_pipeline.inputs['DestBlend']) - shader = create_specular_shader_node(node_tree) + shader = node_tree.nodes.new('ShaderNodeEeveeSpecular') + shader.label = 'Shader' shader.location = (100, 0) shader.inputs['Normal'].hide = True diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index 6896c782..8a72c134 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -31,19 +31,32 @@ def get_or_create_uv_layer(mesh, b_mesh, triangles, tx_coords): return uv_layer.name +def create_materials_from_combinations(mesh, vert_mat_ids, shader_ids, tex_ids): + materials = {} + + if len(vert_mat_ids) == 0: + vert_mat_ids = [vert_mat_ids[0]] * len(mesh.vertices) + if len(shader_ids) == 0: + shader_ids = [shader_ids[0]] * len(mesh.vertices) + if len(tex_ids) == 0: + tex_ids = [tex_ids[0]] * len(tex_ids) + + # TODO + #for i, vertex in enumerate(mesh.vertices): + + + def create_material_passes(context, base_struct, mesh, triangles): b_mesh = bmesh.new() b_mesh.from_mesh(mesh) - for i, mat_pass in enumerate(base_struct.material_passes): + for pass_index, mat_pass in enumerate(base_struct.material_passes): vert_materials = [] shaders = [] textures = [] shader_materials = [] tx_coords = [] - #TODO: create vert_mat - shader - texture combinations - # and support different materials for each triangle for vert_mat_id in mat_pass.vertex_material_ids: vert_materials.append(base_struct.vert_materials[vert_mat_id]) @@ -55,16 +68,15 @@ def create_material_passes(context, base_struct, mesh, triangles): tx_coords.append(tx_stage.tx_coords) for shader_mat_id in mat_pass.shader_material_ids: - shader_materials.append(base_struct.shader_materials[shader_mat_id]) + shader_material = base_struct.shader_materials[shader_mat_id] + create_shader_material(context, mesh, b_mesh, triangles, shader_material, mat_pass.tx_coords) - if mat_pass.tx_coords: - tx_coords.append(mat_pass.tx_coords) - print('vert: ' + str(len(vert_materials))) - print('shaders: ' + str(len(shaders))) - print('textures: ' + str(len(textures))) - print('shader_materials: ' + str(len(shader_materials))) - print('tx_coords: ' + str(len(tx_coords))) + #print('vert: ' + str(len(vert_materials))) + #print('shaders: ' + str(len(shaders))) + #print('textures: ' + str(len(textures))) + #print('shader_materials: ' + str(len(shader_materials))) + #print('tx_coords: ' + str(len(tx_coords))) if vert_materials: texture = None @@ -73,18 +85,16 @@ def create_material_passes(context, base_struct, mesh, triangles): tx_coordinates = None if tx_coords: tx_coordinates = tx_coords[0] - create_vertex_material(context, mesh, b_mesh, triangles, vert_materials[0], shaders[0], texture, tx_coordinates) - - if shader_materials: - create_shader_material(context, mesh, b_mesh, triangles, shader_materials[0], tx_coords[0]) - + #TODO: create vert_mat - shader - texture combinations + # and support different materials for each triangle + create_vertex_material(context, mesh, b_mesh, triangles, vert_materials[0], shaders[0], texture, tx_coordinates, pass_index) ########################################################################## # vertex material ########################################################################## -def create_vertex_material(context, mesh, b_mesh, triangles, vert_mat, shader, texture_struct, tx_coords): +def create_vertex_material(context, mesh, b_mesh, triangles, vert_mat, shader, texture_struct, tx_coords, pass_index): material = bpy.data.materials.new(mesh.name + '.' + vert_mat.vm_name) mesh.materials.append(material) @@ -92,7 +102,7 @@ def create_vertex_material(context, mesh, b_mesh, triangles, vert_mat, shader, t material.shadow_method = 'CLIP' material.blend_method = 'BLEND' material.show_transparent_back = False - #material.pass_index = index + material.pass_index = pass_index material.attributes = {'DEFAULT'} attributes = vert_mat.vm_info.attributes @@ -125,14 +135,15 @@ def create_vertex_material(context, mesh, b_mesh, triangles, vert_mat, shader, t if texture_struct is not None: texture = find_texture(context, texture_struct.file, texture_struct.id) - texture_node = create_texture_node(node_tree, texture) + texture_node = node_tree.nodes.new('ShaderNodeTexImage') + texture_node.image = texture texture_node.location = (-350, 300) links.new(texture_node.outputs['Color'], instance.inputs['Diffuse']) links.new(texture_node.outputs['Alpha'], instance.inputs['DiffuseAlpha']) uv_layer = get_or_create_uv_layer(mesh, b_mesh, triangles, tx_coords) - uv_node = create_uv_map_node(node_tree) + uv_node = node_tree.nodes.new('ShaderNodeUVMap') uv_node.uv_map = uv_layer uv_node.location = (-550, 300) links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) @@ -180,7 +191,8 @@ def create_shader_material(context, mesh, b_mesh, triangles, shader_mat, tx_coor for prop in shader_mat.properties: if prop.type == STRING_PROPERTY and prop.value != '': - texture_node = create_texture_node(node_tree, find_texture(context, prop.value)) + texture_node = node_tree.nodes.new('ShaderNodeTexImage') + texture_node.image = find_texture(context, prop.value) texture_node.location = (-350, y) y -= 300 links.new(texture_node.outputs['Color'], instance.inputs[prop.name]) @@ -188,7 +200,7 @@ def create_shader_material(context, mesh, b_mesh, triangles, shader_mat, tx_coor links.new(texture_node.outputs['Alpha'], instance.inputs[index + 1]) if uv_node is None: - uv_node = create_uv_map_node(node_tree) + uv_node = node_tree.nodes.new('ShaderNodeUVMap') uv_node.uv_map = uv_layer uv_node.location = (-600, 300) links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) diff --git a/io_mesh_w3d/common/utils/node_group_creator.py b/io_mesh_w3d/common/utils/node_group_creator.py index edf35499..29b332b8 100644 --- a/io_mesh_w3d/common/utils/node_group_creator.py +++ b/io_mesh_w3d/common/utils/node_group_creator.py @@ -3,9 +3,7 @@ import os import bpy -from mathutils import Vector from io_mesh_w3d.common.io_xml import * -from io_mesh_w3d.common.node_groups.helpers import * class NodeGroupCreator(): diff --git a/io_mesh_w3d/node_group_templates/alpha_pipeline.xml b/io_mesh_w3d/node_group_templates/alpha_pipeline.xml index 2d1c8d31..2cdcb880 100644 --- a/io_mesh_w3d/node_group_templates/alpha_pipeline.xml +++ b/io_mesh_w3d/node_group_templates/alpha_pipeline.xml @@ -7,7 +7,7 @@ - + @@ -16,7 +16,7 @@ - + diff --git a/tests/common/cases/test_custom_properties.py b/tests/common/cases/test_custom_properties.py index 4ac5d8a6..e0c3b132 100644 --- a/tests/common/cases/test_custom_properties.py +++ b/tests/common/cases/test_custom_properties.py @@ -82,13 +82,6 @@ def test_material_properties(self): mat.surface_type = '32' # other props - - self.assertEqual(0.0, mat.translucency) - mat.translucency = -1.0 - self.assertEqual(0.0, mat.translucency) - mat.translucency = 2.0 - self.assertEqual(1.0, mat.translucency) - self.assertEqual('', mat.vm_args_0) mat.vm_args_0 = 'lorem ipsum' self.assertEqual('lorem ipsum', mat.vm_args_0) @@ -96,118 +89,3 @@ def test_material_properties(self): self.assertEqual('', mat.vm_args_1) mat.vm_args_1 = 'lorem ipsum' self.assertEqual('lorem ipsum', mat.vm_args_1) - - self.assertEqual(0, mat.technique) - mat.technique = -1 - self.assertEqual(0, mat.technique) - mat.technique = 2 - self.assertEqual(1, mat.technique) - - self.assertEqual((1.0, 1.0, 1.0, 0.0), to_vec4(mat.ambient)) - mat.ambient = (-1.0, -1.0, -1.0, -1.0) - self.assertEqual((0.0, 0.0, 0.0, 0.0), to_vec4(mat.ambient)) - mat.ambient = (2.0, 2.0, 2.0, 2.0) - self.assertEqual((1.0, 1.0, 1.0, 1.0), to_vec4(mat.ambient)) - - self.assertEqual((1.0, 1.0, 1.0, 0.0), to_vec4(mat.emission)) - mat.emission = (-1.0, -1.0, -1.0, -1.0) - self.assertEqual((0.0, 0.0, 0.0, 0.0), to_vec4(mat.emission)) - mat.emission = (2.0, 2.0, 2.0, 2.0) - self.assertEqual((1.0, 1.0, 1.0, 1.0), to_vec4(mat.emission)) - - self.assertEqual(0.0, mat.opacity) - mat.opacity = -1.0 - self.assertEqual(0.0, mat.opacity) - mat.opacity = 2.0 - self.assertEqual(1.0, mat.opacity) - - self.assertEqual(True, mat.alpha_test) - - self.assertEqual(0, mat.blend_mode) - - self.assertEqual((0.0, 0.0), to_vec2(mat.bump_uv_scale)) - - self.assertEqual(0, mat.edge_fade_out) - - self.assertEqual(False, mat.depth_write) - - self.assertEqual((0.0, 0.0, 0.0), to_vec3(mat.sampler_clamp_uv_no_mip_0)) - - self.assertEqual((0.0, 0.0, 0.0), to_vec3(mat.sampler_clamp_uv_no_mip_1)) - - self.assertEqual(0, mat.num_textures) - - self.assertEqual('', mat.texture_1) - - self.assertEqual(0, mat.secondary_texture_blend_mode) - - self.assertEqual(0, mat.tex_coord_mapper_0) - - self.assertEqual(0, mat.tex_coord_mapper_1) - - self.assertEqual((0.0, 0.0, 0.0, 0.0), to_vec4(mat.tex_coord_transform_0)) - - self.assertEqual((0.0, 0.0, 0.0, 0.0), to_vec4(mat.tex_coord_transform_1)) - - self.assertEqual('', mat.environment_texture) - - self.assertEqual(0.0, mat.environment_mult) - - self.assertEqual('', mat.recolor_texture) - - self.assertEqual(0.0, mat.recolor_mult) - - self.assertEqual(False, mat.use_recolor) - - self.assertEqual(False, mat.house_color_pulse) - - self.assertEqual('', mat.scrolling_mask_texture) - - self.assertEqual(0.0, mat.tex_coord_transform_angle) - - self.assertEqual(0.0, mat.tex_coord_transform_u_0) - - self.assertEqual(0.0, mat.tex_coord_transform_v_0) - - self.assertEqual(0.0, mat.tex_coord_transform_u_1) - - self.assertEqual(0.0, mat.tex_coord_transform_v_1) - - self.assertEqual(0.0, mat.tex_coord_transform_u_2) - - self.assertEqual(0.0, mat.tex_coord_transform_v_2) - - self.assertEqual((0.0, 0.0, 0.0, 0.0), to_vec4(mat.tex_ani_fps_NPR_lastFrame_frameOffset_0)) - - # shader properties - shader = mat.shader - - self.assertEqual(0, shader.depth_compare) - - self.assertEqual(0, shader.depth_mask) - - self.assertEqual(0, shader.color_mask) - - self.assertEqual(0, shader.dest_blend) - - self.assertEqual(0, shader.fog_func) - - self.assertEqual(0, shader.pri_gradient) - - self.assertEqual(0, shader.sec_gradient) - - self.assertEqual(0, shader.src_blend) - - self.assertEqual(0, shader.texturing) - - self.assertEqual(0, shader.detail_color_func) - - self.assertEqual(0, shader.detail_alpha_func) - - self.assertEqual(0, shader.shader_preset) - - self.assertEqual(0, shader.alpha_test) - - self.assertEqual(0, shader.post_detail_color_func) - - self.assertEqual(0, shader.post_detail_alpha_func) diff --git a/tests/utils.py b/tests/utils.py index 6a7504e4..9b52d569 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -74,9 +74,8 @@ def setUp(self, start): bpy.ops.wm.read_homefile(use_empty=True) addon_utils.enable('io_mesh_w3d', default_set=True) - from io_mesh_w3d.common.utils.material_import import register_alpha_node_group, register_w3d_material_node_group - register_alpha_node_group() - register_w3d_material_node_group() + from io_mesh_w3d.__init__ import register_node_groups + register_node_groups() def tearDown(self): From 7b2c825704d62d288bd7c947e672350e982b2af3 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Tue, 7 Apr 2020 17:21:21 +0200 Subject: [PATCH 36/62] some more work on material export rework --- io_mesh_w3d/common/node_groups/helpers.py | 18 --- .../common/node_groups/vertex_material.py | 14 ++- io_mesh_w3d/common/utils/helpers.py | 18 +++ io_mesh_w3d/common/utils/material_export.py | 81 +++++++++--- io_mesh_w3d/common/utils/material_import.py | 4 +- io_mesh_w3d/common/utils/mesh_export.py | 118 +----------------- io_mesh_w3d/common/utils/mesh_import.py | 8 -- .../common/utils/node_group_creator.py | 1 + 8 files changed, 102 insertions(+), 160 deletions(-) diff --git a/io_mesh_w3d/common/node_groups/helpers.py b/io_mesh_w3d/common/node_groups/helpers.py index 6a7b5f64..e7b94049 100644 --- a/io_mesh_w3d/common/node_groups/helpers.py +++ b/io_mesh_w3d/common/node_groups/helpers.py @@ -6,21 +6,3 @@ def addInputInt(group, name, default=0, min=0, max=255): group.inputs[name].default_value = default group.inputs[name].min_value = min group.inputs[name].max_value = max - - -def get_connected_nodes(links, node, input, types=[]): - nodes = [] - for link in links: - #print(link.to_node) - #print(link.to_socket) - if link.to_node == node and link.to_socket.identifier == input: - # and link.from_socket in outputs: - # and type(node) == bpy.types.ShaderNodeTexture.... - # and node.inputs[''].is_linked - nodes.append(link.from_node) - - for node in nodes: - print('###') - print(node.bl_idname) - print(node.name) - return nodes \ No newline at end of file diff --git a/io_mesh_w3d/common/node_groups/vertex_material.py b/io_mesh_w3d/common/node_groups/vertex_material.py index 22d2b4f7..3a66c4bc 100644 --- a/io_mesh_w3d/common/node_groups/vertex_material.py +++ b/io_mesh_w3d/common/node_groups/vertex_material.py @@ -5,6 +5,7 @@ from io_mesh_w3d.common.node_groups.helpers import * + class VertexMaterialGroup(): name = 'VertexMaterial' @@ -54,8 +55,9 @@ def register(name): group_inputs.location = (-350,0) group.inputs.new('NodeSocketColor', 'Diffuse') group.inputs['Diffuse'].default_value = (0.8, 0.8, 0.8, 1.0) - group.inputs.new('NodeSocketFloat', 'DiffuseAlpha') - group.inputs['DiffuseAlpha'].default_value = 1.0 + group.inputs.new('NodeSocketColor', 'DiffuseTexture') + group.inputs.new('NodeSocketFloat', 'DiffuseTextureAlpha') + group.inputs['DiffuseTextureAlpha'].default_value = 1.0 addInputInt(group, 'DestBlend', max=1) group.inputs.new('NodeSocketColor', 'Ambient') group.inputs['Ambient'].default_value = (0.8, 0.8, 0.8, 1.0) @@ -91,8 +93,8 @@ def register(name): alpha_pipeline = node_tree.nodes.new(type='ShaderNodeGroup') alpha_pipeline.location = (-100, 0) alpha_pipeline.node_tree = bpy.data.node_groups['AlphaPipeline'] - links.new(group_inputs.outputs['Diffuse'], alpha_pipeline.inputs['Diffuse']) - links.new(group_inputs.outputs['DiffuseAlpha'], alpha_pipeline.inputs['Alpha']) + links.new(group_inputs.outputs['DiffuseTexture'], alpha_pipeline.inputs['Diffuse']) + links.new(group_inputs.outputs['DiffuseTextureAlpha'], alpha_pipeline.inputs['Alpha']) links.new(group_inputs.outputs['DestBlend'], alpha_pipeline.inputs['DestBlend']) shader = node_tree.nodes.new('ShaderNodeEeveeSpecular') @@ -100,7 +102,7 @@ def register(name): shader.location = (100, 0) shader.inputs['Normal'].hide = True - links.new(group_inputs.outputs['Diffuse'], shader.inputs['Base Color']) + links.new(group_inputs.outputs['DiffuseTexture'], shader.inputs['Base Color']) links.new(group_inputs.outputs['Specular'], shader.inputs['Specular']) links.new(group_inputs.outputs['Shininess'], shader.inputs['Roughness']) links.new(group_inputs.outputs['Emissive'], shader.inputs['Emissive Color']) @@ -118,4 +120,4 @@ class PrelitLightmapMultiPassGroup(VertexMaterialGroup): name = 'PrelitLightmapMultiPass' class PrelitLightmapMultiTextureGroup(VertexMaterialGroup): - name = 'PrelitLightmapMultiTextue' \ No newline at end of file + name = 'PrelitLightmapMultiTextue' diff --git a/io_mesh_w3d/common/utils/helpers.py b/io_mesh_w3d/common/utils/helpers.py index 99b73ec0..7f8190b0 100644 --- a/io_mesh_w3d/common/utils/helpers.py +++ b/io_mesh_w3d/common/utils/helpers.py @@ -127,3 +127,21 @@ def find_texture(context, file, name=None): img.name = name img.alpha_mode = 'STRAIGHT' return img + + +def get_connected_nodes(node_tree, node, socket_id, types=[]): + result = [] + for link in node_tree.links: + if link.to_node == node and link.to_socket.name == socket_id: + if types: + if link.from_node.bl_idname in types: + result.append(link.from_node) + else: + result.append(link.from_node) + if link.from_node == node and link.from_socket.name == socket_id: + if types: + if link.to_node.bl_idname in types: + result.append(link.to_node) + else: + result.append(link.to_node) + return result \ No newline at end of file diff --git a/io_mesh_w3d/common/utils/material_export.py b/io_mesh_w3d/common/utils/material_export.py index 80da35cf..9381a01b 100644 --- a/io_mesh_w3d/common/utils/material_export.py +++ b/io_mesh_w3d/common/utils/material_export.py @@ -16,6 +16,23 @@ def append_texture_if_valid(texture, used_textures): return used_textures + +def retrieve_material(context, material): + # Material Output + output = None + for node in material.node_tree.nodes: + if node.bl_idname == 'ShaderNodeOutputMaterial': + output = node + + shader_node = get_connected_nodes(material.node_tree, output, 'Surface', ['ShaderNodeGroup'])[0] + + vertex_materials_ids = [VertexMaterialGroup.name, PrelitUnlitGroup.name, PrelitVertexGroup.name, + PrelitLightmapMultiPassGroup.name, PrelitLightmapMultiTextureGroup.name] + + if shader_node.node_tree.name in vertex_materials_ids: + retrieve_vertex_material(material, shader_node) + + def get_used_textures(material, principled, used_textures): used_textures = append_texture_if_valid(principled.base_color_texture, used_textures) used_textures = append_texture_if_valid(principled.normalmap_texture, used_textures) @@ -28,16 +45,19 @@ def get_used_textures(material, principled, used_textures): return used_textures -def retrieve_vertex_material(material): +def retrieve_vertex_material(material, shader_node): + # TODO: handle connected nodes + print(RGBA(vec=shader_node.inputs['Diffuse'].default_value)) + info = VertexMaterialInfo( attributes=0, shininess=material.specular_intensity, - specular=RGBA(vec=material.specular_color, a=0), - diffuse=RGBA(vec=material.diffuse_color, a=0), - emissive=RGBA(vec=material.emission), - ambient=RGBA(vec=material.ambient), - translucency=material.translucency, - opacity=material.opacity) + specular=RGBA(vec=shader_node.inputs['Specular'].default_value), + diffuse=RGBA(vec=shader_node.inputs['Diffuse'].default_value), + emissive=RGBA(vec=shader_node.inputs['Emissive'].default_value), + ambient=RGBA(vec=shader_node.inputs['Ambient'].default_value), + translucency=shader_node.inputs['Translucency'].default_value, + opacity=shader_node.inputs['Opacity'].default_value) if 'USE_DEPTH_CUE' in material.attributes: info.attributes |= USE_DEPTH_CUE @@ -48,13 +68,46 @@ def retrieve_vertex_material(material): if 'DEPTH_CUE_TO_ALPHA' in material.attributes: info.attributes |= DEPTH_CUE_TO_ALPHA - vert_material = VertexMaterial( - vm_name=material.name.split('.', 1)[-1], - vm_info=info, - vm_args_0=material.vm_args_0, - vm_args_1=material.vm_args_1) - - return vert_material + #if shader_node.node_tree.name == VertexMaterialGroup.name: + #elif shader_node.node_tree.name == PrelitUnlitGroup.name: + #elif shader_node.node_tree.name == PrelitVertexGroup.name: + #elif shader_node.node_tree.name == PrelitLightmapMultiPassGroup.name: + #elif shader_node.node_tree.name == PrelitLightmapMultiTextureGroup.name: + + vert_mat = VertexMaterial() + vert_mat.vm_name = shader_node.label + vert_mat.vm_info = info + vert_mat.vm_args_0 = material.vm_args_0 + vert_mat.vm_args_1 = material.vm_args_1 + + shader = Shader( + depth_compare=shader_node.inputs['DepthCompare'].default_value, + depth_mask=shader_node.inputs['DepthMask'].default_value, + color_mask=shader_node.inputs['ColorMask'].default_value, + dest_blend=shader_node.inputs['DestBlend'].default_value, + fog_func=shader_node.inputs['FogFunc'].default_value, + pri_gradient=shader_node.inputs['PriGradient'].default_value, + sec_gradient=shader_node.inputs['SecGradient'].default_value, + src_blend=shader_node.inputs['SrcBlend'].default_value, + texturing=shader_node.inputs['Texturing'].default_value, + detail_color_func=shader_node.inputs['DetailColorFunc'].default_value, + detail_alpha_func=shader_node.inputs['DetailAlphaFunc'].default_value, + shader_preset=shader_node.inputs['Preset'].default_value, + alpha_test=shader_node.inputs['AlphaTest'].default_value, + post_detail_color_func=shader_node.inputs['PostDetailColorFunc'].default_value, + post_detail_alpha_func=shader_node.inputs['PostDetailAlphaFunc'].default_value) + + + texture_nodes = get_connected_nodes(material.node_tree, shader_node, 'DiffuseTexture') + + if texture_nodes: + print(texture_nodes[0].image.name) + print(texture_nodes[0].bl_idname) + + # TODO: get texture + # return (vert_mat, shader, texture, mat_pass_index) + + return vert_mat def append_property(shader_mat, type, name, value, default=None): diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index 8a72c134..333b3abb 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -138,8 +138,8 @@ def create_vertex_material(context, mesh, b_mesh, triangles, vert_mat, shader, t texture_node = node_tree.nodes.new('ShaderNodeTexImage') texture_node.image = texture texture_node.location = (-350, 300) - links.new(texture_node.outputs['Color'], instance.inputs['Diffuse']) - links.new(texture_node.outputs['Alpha'], instance.inputs['DiffuseAlpha']) + links.new(texture_node.outputs['Color'], instance.inputs['DiffuseTexture']) + links.new(texture_node.outputs['Alpha'], instance.inputs['DiffuseTextureAlpha']) uv_layer = get_or_create_uv_layer(mesh, b_mesh, triangles, tx_coords) diff --git a/io_mesh_w3d/common/utils/mesh_export.py b/io_mesh_w3d/common/utils/mesh_export.py index 7bfa4c86..fd7da1a3 100644 --- a/io_mesh_w3d/common/utils/mesh_export.py +++ b/io_mesh_w3d/common/utils/mesh_export.py @@ -149,118 +149,12 @@ def retrieve_meshes(context, hierarchy, rig, container_name, force_vertex_materi for i, material in enumerate(mesh.materials): mat_pass = MaterialPass() - principled = node_shader_utils.PrincipledBSDFWrapper(material, is_readonly=True) - - used_textures = get_used_textures(material, principled, used_textures) - - if context.file_format == 'W3X' or ( - material.material_type == 'SHADER_MATERIAL' and not force_vertex_materials): - mat_pass.shader_material_ids = [i] - if i < len(tx_stages): - mat_pass.tx_coords = tx_stages[i].tx_coords - mesh_struct.shader_materials.append( - retrieve_shader_material(context, material, principled)) - mesh_struct.material_passes.append(mat_pass) - else: - shader = retrieve_shader(material) - - if i < len(tx_stages): - mat_pass.tx_stages.append(tx_stages[i]) - - vert_material = retrieve_vertex_material(material) - - tex = None - if principled.base_color_texture.image is not None: - info = TextureInfo() - img = principled.base_color_texture.image - filepath = os.path.basename(img.filepath) - if filepath == '': - filepath = img.name + '.dds' - tex = Texture( - id=img.name, - file=filepath, - texture_info=info) - - #print('material type: ' + material.material_type) - if material.material_type == 'VERTEX_MATERIAL': - mat_pass.shader_ids = [i] - mat_pass.vertex_material_ids = [i] - mat_pass.tx_stages[0].tx_ids = [0] - mesh_struct.shaders.append(shader) - mesh_struct.vert_materials.append(vert_material) - mesh_struct.material_passes.append(mat_pass) - if tex is not None: - mesh_struct.textures.append(tex) - else: - #print('prelit type: ' + material.prelit_type) - if material.prelit_type == 'PRELIT_UNLIT': - if mesh_struct.prelit_unlit is None: - mesh_struct.prelit_unlit = PrelitBase( - type=W3D_CHUNK_PRELIT_UNLIT, - shaders=[], - vert_materials=[], - material_passes=[], - textures=[]) - - mat_pass.tx_stages[0].tx_ids = [0] - mat_pass.shader_ids = [len(mesh_struct.prelit_unlit.shaders)] - mat_pass.vertex_material_ids = [len(mesh_struct.prelit_unlit.vert_materials)] - mesh_struct.prelit_unlit.shaders.append(shader) - mesh_struct.prelit_unlit.vert_materials.append(vert_material) - mesh_struct.prelit_unlit.material_passes.append(mat_pass) - if tex is not None: - mesh_struct.prelit_unlit.textures.append(tex) - - elif material.prelit_type == 'PRELIT_VERTEX': - if mesh_struct.prelit_vertex is None: - mesh_struct.prelit_vertex = PrelitBase(type=W3D_CHUNK_PRELIT_VERTEX, - shaders=[], - vert_materials=[], - material_passes=[], - textures=[]) - - mat_pass.tx_stages[0].tx_ids = [0] - mat_pass.shader_ids = [len(mesh_struct.prelit_vertex.shaders)] - mat_pass.vertex_material_ids = [len(mesh_struct.prelit_vertex.vert_materials)] - mesh_struct.prelit_vertex.shaders.append(shader) - mesh_struct.prelit_vertex.vert_materials.append(vert_material) - mesh_struct.prelit_vertex.material_passes.append(mat_pass) - if tex is not None: - mesh_struct.prelit_vertex.textures.append(tex) - - elif material.prelit_type == 'PRELIT_LIGHTMAP_MULTI_PASS': - if mesh_struct.prelit_lightmap_multi_pass is None: - mesh_struct.prelit_lightmap_multi_pass = PrelitBase(type=W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_PASS, - shaders=[], - vert_materials=[], - material_passes=[], - textures=[]) - - mat_pass.tx_stages[0].tx_ids = [0] - mat_pass.shader_ids = [len(mesh_struct.prelit_lightmap_multi_pass.shaders)] - mat_pass.vertex_material_ids = [len(mesh_struct.prelit_lightmap_multi_pass.vert_materials)] - mesh_struct.prelit_lightmap_multi_pass.shaders.append(shader) - mesh_struct.prelit_lightmap_multi_pass.vert_materials.append(vert_material) - mesh_struct.prelit_lightmap_multi_pass.material_passes.append(mat_pass) - if tex is not None: - mesh_struct.prelit_lightmap_multi_pass.textures.append(tex) - - elif material.prelit_type == 'PRELIT_LIGHTMAP_MULTI_TEXTURE': - if mesh_struct.prelit_lightmap_multi_texture is None: - mesh_struct.prelit_lightmap_multi_texture = PrelitBase(type=W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_TEXTURE, - shaders=[], - vert_materials=[], - material_passes=[], - textures=[]) - - mat_pass.tx_stages[0].tx_ids = [0] - mat_pass.shader_ids = [len(mesh_struct.prelit_lightmap_multi_texture.shaders)] - mat_pass.vertex_material_ids = [len(mesh_struct.prelit_lightmap_multi_texture.vert_materials)] - mesh_struct.prelit_lightmap_multi_texture.shaders.append(shader) - mesh_struct.prelit_lightmap_multi_texture.vert_materials.append(vert_material) - mesh_struct.prelit_lightmap_multi_texture.material_passes.append(mat_pass) - if tex is not None: - mesh_struct.prelit_lightmap_multi_texture.textures.append(tex) + #principled = node_shader_utils.PrincipledBSDFWrapper(material, is_readonly=True) + + #used_textures = get_used_textures(material, principled, used_textures) + + retrieve_material(context, material) + header.vert_channel_flags = VERTEX_CHANNEL_LOCATION | VERTEX_CHANNEL_NORMAL diff --git a/io_mesh_w3d/common/utils/mesh_import.py b/io_mesh_w3d/common/utils/mesh_import.py index 3545a877..45cfc241 100644 --- a/io_mesh_w3d/common/utils/mesh_import.py +++ b/io_mesh_w3d/common/utils/mesh_import.py @@ -32,14 +32,6 @@ def create_mesh(context, mesh_struct, coll): create_material_passes(context, mesh_struct, mesh, triangles) - # create_shader_materials(context, mesh_struct, mesh, triangles) - - #create_vertex_materials(context, mesh_struct, mesh, triangles) - #create_vertex_materials(context, mesh_struct.prelit_unlit, mesh, triangles, prelit_type='PRELIT_UNLIT') - #create_vertex_materials(context, mesh_struct.prelit_vertex, mesh, triangles, prelit_type='PRELIT_VERTEX') - #create_vertex_materials(context, mesh_struct.prelit_lightmap_multi_pass, mesh, triangles, prelit_type='PRELIT_LIGHTMAP_MULTI_PASS') - #create_vertex_materials(context, mesh_struct.prelit_lightmap_multi_texture, mesh, triangles, prelit_type='PRELIT_LIGHTMAP_MULTI_TEXTURE') - def rig_mesh(mesh_struct, hierarchy, rig, sub_object=None): mesh_ob = bpy.data.objects[mesh_struct.name()] diff --git a/io_mesh_w3d/common/utils/node_group_creator.py b/io_mesh_w3d/common/utils/node_group_creator.py index 29b332b8..a28e712c 100644 --- a/io_mesh_w3d/common/utils/node_group_creator.py +++ b/io_mesh_w3d/common/utils/node_group_creator.py @@ -54,6 +54,7 @@ def process_max_value(self, node_tree, input, type, max): max = int(max) node_tree.inputs[input].max_value = max + def process_presets(self, node_tree, xml_node, name=None, type=None): if type is None: type = xml_node.get('type') From 2151f92a6f253d0103ec0022407fed5a8879c027 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Wed, 8 Apr 2020 21:58:50 +0200 Subject: [PATCH 37/62] more work on vertex material export --- .../common/node_groups/vertex_material.py | 3 +- io_mesh_w3d/common/utils/helpers.py | 88 ++++++++++++--- io_mesh_w3d/common/utils/material_export.py | 102 +++++++----------- io_mesh_w3d/common/utils/material_import.py | 3 + .../common/utils/node_group_creator.py | 47 ++++---- io_mesh_w3d/node_group_templates/BasicW3D.xml | 2 +- 6 files changed, 138 insertions(+), 107 deletions(-) diff --git a/io_mesh_w3d/common/node_groups/vertex_material.py b/io_mesh_w3d/common/node_groups/vertex_material.py index 3a66c4bc..df099b9d 100644 --- a/io_mesh_w3d/common/node_groups/vertex_material.py +++ b/io_mesh_w3d/common/node_groups/vertex_material.py @@ -5,7 +5,6 @@ from io_mesh_w3d.common.node_groups.helpers import * - class VertexMaterialGroup(): name = 'VertexMaterial' @@ -57,7 +56,7 @@ def register(name): group.inputs['Diffuse'].default_value = (0.8, 0.8, 0.8, 1.0) group.inputs.new('NodeSocketColor', 'DiffuseTexture') group.inputs.new('NodeSocketFloat', 'DiffuseTextureAlpha') - group.inputs['DiffuseTextureAlpha'].default_value = 1.0 + group.inputs['DiffuseTextureAlpha'].default_value = 0.0 addInputInt(group, 'DestBlend', max=1) group.inputs.new('NodeSocketColor', 'Ambient') group.inputs['Ambient'].default_value = (0.8, 0.8, 0.8, 1.0) diff --git a/io_mesh_w3d/common/utils/helpers.py b/io_mesh_w3d/common/utils/helpers.py index 7f8190b0..009ed6df 100644 --- a/io_mesh_w3d/common/utils/helpers.py +++ b/io_mesh_w3d/common/utils/helpers.py @@ -5,6 +5,7 @@ import os from mathutils import Quaternion, Matrix from bpy_extras.image_utils import load_image +from io_mesh_w3d.common.structs.rgba import RGBA def make_transform_matrix(loc, rot): @@ -129,19 +130,74 @@ def find_texture(context, file, name=None): return img -def get_connected_nodes(node_tree, node, socket_id, types=[]): - result = [] - for link in node_tree.links: - if link.to_node == node and link.to_socket.name == socket_id: - if types: - if link.from_node.bl_idname in types: - result.append(link.from_node) - else: - result.append(link.from_node) - if link.from_node == node and link.from_socket.name == socket_id: - if types: - if link.to_node.bl_idname in types: - result.append(link.to_node) - else: - result.append(link.to_node) - return result \ No newline at end of file +def get_color_value(context, node_tree, node, input): + type = 'ShaderNodeRGB' + socket = node.inputs[input] + if not socket.is_linked: + return RGBA(vec=socket.default_value) + for link in socket.links: + if link.from_node.bl_idname == type: + return RGBA(vec=link.from_node.outputs['Color'].default_value) + else: + context.error('Node ' + link.from_node.bl_idname + ' connected to ' + input + ' in ' + node_tree.name + ' is not of type ' + type) + return RGBA() + + +def get_uv_value(context, node_tree, node, input): + type = 'ShaderNodeUVMap' + socket = node.inputs[input] + if not socket.is_linked: + return None + for link in socket.links: + if link.from_node.bl_idname == type: + return link.from_node.uv_map + else: + context.error('Node ' + link.from_node.bl_idname + ' connected to ' + input + ' in ' + node_tree.name + ' is not of type ' + type) + return None + + +def get_texture_value(context, node_tree, node, input): + type = 'ShaderNodeTexImage' + socket = node.inputs[input] + if not socket.is_linked: + return (None, None) + for link in socket.links: + if link.from_node.bl_idname == type: + return (link.from_node.image.name, get_uv_value(context, node_tree, link.from_node, 'Vector')) + else: + context.error('Node ' + link.from_node.bl_idname + ' connected to ' + input + ' in ' + node_tree.name + ' is not of type ' + type) + return (None, None) + + +def get_value(context, node_tree, node, input, cast): + type = 'ShaderNodeValue' + socket = node.inputs[input] + if not socket.is_linked: + return cast(socket.default_value) + for link in socket.links: + if link.from_node.bl_idname == type: + return cast(link.from_node.outputs['Value'].default_value) + else: + context.error('Node ' + link.from_node.bl_idname + ' connected to ' + input + ' in ' + node_tree.name + ' is not of type ' + type) + return cast(0) + +def get_shader_node_group(context, node_tree): + output_node = None + + for node in node_tree.nodes: + if node.bl_idname == 'ShaderNodeOutputMaterial': + output_node = node + break + + if output_node is None: + return None + + socket = output_node.inputs['Surface'] + if not socket.is_linked: + return None + + for link in socket.links: + if link.from_node.bl_idname == 'ShaderNodeGroup': + return link.from_node + # TODO: handle the default PrincipledBSDF here + return None \ No newline at end of file diff --git a/io_mesh_w3d/common/utils/material_export.py b/io_mesh_w3d/common/utils/material_export.py index 9381a01b..1445ad62 100644 --- a/io_mesh_w3d/common/utils/material_export.py +++ b/io_mesh_w3d/common/utils/material_export.py @@ -7,57 +7,29 @@ from io_mesh_w3d.common.structs.mesh_structs.shader_material import * -def append_texture_if_valid(texture, used_textures): - if isinstance(texture, str): - if texture != '' and texture not in used_textures: - used_textures.append(texture) - elif texture is not None and texture.image is not None and texture.image.name not in used_textures: - used_textures.append(texture.image.name) - return used_textures - - - def retrieve_material(context, material): - # Material Output - output = None - for node in material.node_tree.nodes: - if node.bl_idname == 'ShaderNodeOutputMaterial': - output = node - - shader_node = get_connected_nodes(material.node_tree, output, 'Surface', ['ShaderNodeGroup'])[0] - vertex_materials_ids = [VertexMaterialGroup.name, PrelitUnlitGroup.name, PrelitVertexGroup.name, PrelitLightmapMultiPassGroup.name, PrelitLightmapMultiTextureGroup.name] - if shader_node.node_tree.name in vertex_materials_ids: - retrieve_vertex_material(material, shader_node) - - -def get_used_textures(material, principled, used_textures): - used_textures = append_texture_if_valid(principled.base_color_texture, used_textures) - used_textures = append_texture_if_valid(principled.normalmap_texture, used_textures) - used_textures = append_texture_if_valid(principled.specular_texture, used_textures) + shader_node = get_shader_node_group(context, material.node_tree) - used_textures = append_texture_if_valid(material.texture_1, used_textures) - used_textures = append_texture_if_valid(material.environment_texture, used_textures) - used_textures = append_texture_if_valid(material.recolor_texture, used_textures) - used_textures = append_texture_if_valid(material.scrolling_mask_texture, used_textures) - return used_textures + if shader_node.node_tree.name in vertex_materials_ids: + retrieve_vertex_material(context, material, shader_node) + # else: shader material -def retrieve_vertex_material(material, shader_node): - # TODO: handle connected nodes - print(RGBA(vec=shader_node.inputs['Diffuse'].default_value)) +def retrieve_vertex_material(context, material, shader_node): + node_tree = material.node_tree info = VertexMaterialInfo( attributes=0, shininess=material.specular_intensity, - specular=RGBA(vec=shader_node.inputs['Specular'].default_value), - diffuse=RGBA(vec=shader_node.inputs['Diffuse'].default_value), - emissive=RGBA(vec=shader_node.inputs['Emissive'].default_value), - ambient=RGBA(vec=shader_node.inputs['Ambient'].default_value), - translucency=shader_node.inputs['Translucency'].default_value, - opacity=shader_node.inputs['Opacity'].default_value) + specular=get_color_value(context, node_tree, shader_node, 'Specular'), + diffuse=get_color_value(context, node_tree, shader_node, 'Diffuse'), + emissive=get_color_value(context, node_tree, shader_node, 'Emissive'), + ambient=get_color_value(context, node_tree, shader_node, 'Ambient'), + translucency=get_value(context, node_tree, shader_node, 'Translucency', float), + opacity=get_value(context, node_tree, shader_node, 'Opacity', float)) if 'USE_DEPTH_CUE' in material.attributes: info.attributes |= USE_DEPTH_CUE @@ -77,36 +49,34 @@ def retrieve_vertex_material(material, shader_node): vert_mat = VertexMaterial() vert_mat.vm_name = shader_node.label vert_mat.vm_info = info + # TODO: handle these vert_mat.vm_args_0 = material.vm_args_0 vert_mat.vm_args_1 = material.vm_args_1 shader = Shader( - depth_compare=shader_node.inputs['DepthCompare'].default_value, - depth_mask=shader_node.inputs['DepthMask'].default_value, - color_mask=shader_node.inputs['ColorMask'].default_value, - dest_blend=shader_node.inputs['DestBlend'].default_value, - fog_func=shader_node.inputs['FogFunc'].default_value, - pri_gradient=shader_node.inputs['PriGradient'].default_value, - sec_gradient=shader_node.inputs['SecGradient'].default_value, - src_blend=shader_node.inputs['SrcBlend'].default_value, - texturing=shader_node.inputs['Texturing'].default_value, - detail_color_func=shader_node.inputs['DetailColorFunc'].default_value, - detail_alpha_func=shader_node.inputs['DetailAlphaFunc'].default_value, - shader_preset=shader_node.inputs['Preset'].default_value, - alpha_test=shader_node.inputs['AlphaTest'].default_value, - post_detail_color_func=shader_node.inputs['PostDetailColorFunc'].default_value, - post_detail_alpha_func=shader_node.inputs['PostDetailAlphaFunc'].default_value) - - - texture_nodes = get_connected_nodes(material.node_tree, shader_node, 'DiffuseTexture') - - if texture_nodes: - print(texture_nodes[0].image.name) - print(texture_nodes[0].bl_idname) - - # TODO: get texture - # return (vert_mat, shader, texture, mat_pass_index) - + depth_compare=get_value(context, node_tree, shader_node, 'DepthCompare', int), + depth_mask=get_value(context, node_tree, shader_node, 'DepthMask', int), + color_mask=get_value(context, node_tree, shader_node, 'ColorMask', int), + dest_blend=get_value(context, node_tree, shader_node, 'DestBlend', int), + fog_func=get_value(context, node_tree, shader_node, 'FogFunc', int), + pri_gradient=get_value(context, node_tree, shader_node, 'PriGradient', int), + sec_gradient=get_value(context, node_tree, shader_node, 'SecGradient', int), + src_blend=get_value(context, node_tree, shader_node, 'SrcBlend', int), + texturing=get_value(context, node_tree, shader_node, 'Texturing', int), #TODO: set this based on applied texture + detail_color_func=get_value(context, node_tree, shader_node, 'DetailColorFunc', int), + detail_alpha_func=get_value(context, node_tree, shader_node, 'DetailAlphaFunc', int), + shader_preset=get_value(context, node_tree, shader_node, 'Preset', int), + alpha_test=get_value(context, node_tree, shader_node, 'AlphaTest', int), + post_detail_color_func=get_value(context, node_tree, shader_node, 'PostDetailColorFunc', int), + post_detail_alpha_func=get_value(context, node_tree, shader_node, 'PostDetailAlphaFunc', int)) + + (texture, uv_map) = get_texture_value(context, node_tree, shader_node, 'DiffuseTexture') + + texture_struct = Texture(file=texture) + tx_coords = + + + #return vert_mat, shader, texture_struct, tx_coords, pass_index, prelit_type return vert_mat diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index 333b3abb..9503c4c6 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -195,6 +195,9 @@ def create_shader_material(context, mesh, b_mesh, triangles, shader_mat, tx_coor texture_node.image = find_texture(context, prop.value) texture_node.location = (-350, y) y -= 300 + + instance.inputs[prop.name].display_shape = 'SQUARE' + links.new(texture_node.outputs['Color'], instance.inputs[prop.name]) index = instance.inputs.keys().index(prop.name) links.new(texture_node.outputs['Alpha'], instance.inputs[index + 1]) diff --git a/io_mesh_w3d/common/utils/node_group_creator.py b/io_mesh_w3d/common/utils/node_group_creator.py index a28e712c..0ebc3931 100644 --- a/io_mesh_w3d/common/utils/node_group_creator.py +++ b/io_mesh_w3d/common/utils/node_group_creator.py @@ -20,50 +20,48 @@ def process_input_hides(self, xml_node, node): node.outputs[id].hide = True - def process_default_value(self, node_tree, input, type, default): + def process_default_value(self, socket, default): if default is None: return - if type == 'NodeSocketFloat': + if socket.type == 'VALUE': default = float(default) - elif type == 'NodeSocketInt': + elif socket.type == 'INT': default = int(default) - elif type == 'NodeSocketBool': + elif socket.type == 'BOOLEAN': default = int(default) - elif type == 'NodeSocketColor': + elif socket.type == 'RGBA': values = default.split(',') default = Vector((float(values[0]), float(values[1]), float(values[2]), float(values[3]))) - node_tree.inputs[input].default_value = default + socket.default_value = default - def process_min_value(self, node_tree, input, type, min): + def process_min_value(self, socket, min): if min is None: return - if type == 'NodeSocketFloat': + if socket.type == 'FLOAT': min = float(min) - elif type == 'NodeSocketInt': + elif socket.type == 'INT': min = int(min) - node_tree.inputs[input].min_value = min + socket.min_value = min - def process_max_value(self, node_tree, input, type, max): + def process_max_value(self, socket, max): if max is None: return - if type == 'NodeSocketFloat': + if socket.type == 'FLOAT': max = float(max) - elif type == 'NodeSocketInt': + elif socket.type == 'INT': max = int(max) - node_tree.inputs[input].max_value = max + socket.max_value = max - def process_presets(self, node_tree, xml_node, name=None, type=None): - if type is None: - type = xml_node.get('type') + def process_presets(self, socket, xml_node, name=None): if name is None: name = xml_node.get('name', xml_node.get('id')) - self.process_default_value(node_tree, name, type, xml_node.get('default')) - self.process_min_value(node_tree, name, type, xml_node.get('min')) - self.process_max_value(node_tree, name, type, xml_node.get('max')) + self.process_default_value(socket, xml_node.get('default')) + self.process_min_value(socket, xml_node.get('min')) + self.process_max_value(socket, xml_node.get('max')) def create_input_node(self, node_tree, xml_node, node): @@ -72,8 +70,13 @@ def create_input_node(self, node_tree, xml_node, node): continue type = child_node.get('type') name = child_node.get('name') - node_tree.inputs.new(type, name) - self.process_presets(node_tree, child_node, name, type) + shape = 'CIRCLE' + + if type == 'NodeSocketTexture': + type = 'NodeSocketColor' + + socket = node_tree.inputs.new(type, name) + self.process_presets(socket, child_node, name) def create_output_node(self, node_tree, xml_node, node): diff --git a/io_mesh_w3d/node_group_templates/BasicW3D.xml b/io_mesh_w3d/node_group_templates/BasicW3D.xml index f2c2c3f8..c498c46d 100644 --- a/io_mesh_w3d/node_group_templates/BasicW3D.xml +++ b/io_mesh_w3d/node_group_templates/BasicW3D.xml @@ -4,7 +4,7 @@ - + From ef83a9d7aa7f1c22fa1f25d5b3578bf96ae6a9db Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Thu, 9 Apr 2020 01:44:18 +0200 Subject: [PATCH 38/62] continued work on material export --- io_mesh_w3d/common/utils/helpers.py | 60 +++++- io_mesh_w3d/common/utils/material_export.py | 173 ++++-------------- io_mesh_w3d/common/utils/mesh_export.py | 12 +- .../common/utils/node_group_creator.py | 1 - 4 files changed, 98 insertions(+), 148 deletions(-) diff --git a/io_mesh_w3d/common/utils/helpers.py b/io_mesh_w3d/common/utils/helpers.py index 009ed6df..4522e9e4 100644 --- a/io_mesh_w3d/common/utils/helpers.py +++ b/io_mesh_w3d/common/utils/helpers.py @@ -155,10 +155,8 @@ def get_uv_value(context, node_tree, node, input): context.error('Node ' + link.from_node.bl_idname + ' connected to ' + input + ' in ' + node_tree.name + ' is not of type ' + type) return None - -def get_texture_value(context, node_tree, node, input): +def get_texture_value(context, node_tree, socket): type = 'ShaderNodeTexImage' - socket = node.inputs[input] if not socket.is_linked: return (None, None) for link in socket.links: @@ -169,6 +167,11 @@ def get_texture_value(context, node_tree, node, input): return (None, None) +def get_texture_value(context, node_tree, node, input): + socket = node.inputs[input] + return get_texture_value(context, node_tree, socket) + + def get_value(context, node_tree, node, input, cast): type = 'ShaderNodeValue' socket = node.inputs[input] @@ -200,4 +203,53 @@ def get_shader_node_group(context, node_tree): if link.from_node.bl_idname == 'ShaderNodeGroup': return link.from_node # TODO: handle the default PrincipledBSDF here - return None \ No newline at end of file + return None + +def get_group_input_types(filename): + dirname = os.path.dirname(__file__) + directory = os.path.join(up(up(dirname)), 'node_group_templates') + + path = os.path.join(directory, filename) + root = find_root(None, path) + if root is None: + return {} + + name = root.get('name') + if name.replace('.fx', '') != filename.replace('.xml', ''): + return {} + + links = node_tree.links + inputs = {} + + for xml_node in root: + if xml_node.tag == 'parent': + parent = xml_node.get('file') + inputs = get_group_input_types(parent) + elif xml_node.tag == 'node': + type = xml_node.get('type') + if type != 'NodeGroupInput': + continue + + for child_node in xml_node: + if child_node.tag != 'input': + continue + + type = child_node.get('type') + if type == 'ShaderNodeTexture': + default = child_node.get('default', None) + elif type == 'ShaderNodeFloat': + default = child_node.get('default', 0.0) + elif type == 'ShaderNodeVector2': + default = child_node.get('default', Vector((0.0, 0.0))) + elif type == 'ShaderNodeVector': + default = child_node.get('default', Vector((0.0, 0.0, 0.0))) + elif type == 'ShaderNodeVector4': + default = child_node.get('default', Vector((0.0, 0.0, 0.0, 0.0))) + elif type == 'ShaderNodeInt': + default = child_node.get('default', 0) + elif type == 'ShaderNodeByte': + default = child_node.get('default', 0) + + inputs[child_node.get('name')] = (type, default) + + return inputs \ No newline at end of file diff --git a/io_mesh_w3d/common/utils/material_export.py b/io_mesh_w3d/common/utils/material_export.py index 1445ad62..4ea6a349 100644 --- a/io_mesh_w3d/common/utils/material_export.py +++ b/io_mesh_w3d/common/utils/material_export.py @@ -40,12 +40,6 @@ def retrieve_vertex_material(context, material, shader_node): if 'DEPTH_CUE_TO_ALPHA' in material.attributes: info.attributes |= DEPTH_CUE_TO_ALPHA - #if shader_node.node_tree.name == VertexMaterialGroup.name: - #elif shader_node.node_tree.name == PrelitUnlitGroup.name: - #elif shader_node.node_tree.name == PrelitVertexGroup.name: - #elif shader_node.node_tree.name == PrelitLightmapMultiPassGroup.name: - #elif shader_node.node_tree.name == PrelitLightmapMultiTextureGroup.name: - vert_mat = VertexMaterial() vert_mat.vm_name = shader_node.label vert_mat.vm_info = info @@ -62,7 +56,7 @@ def retrieve_vertex_material(context, material, shader_node): pri_gradient=get_value(context, node_tree, shader_node, 'PriGradient', int), sec_gradient=get_value(context, node_tree, shader_node, 'SecGradient', int), src_blend=get_value(context, node_tree, shader_node, 'SrcBlend', int), - texturing=get_value(context, node_tree, shader_node, 'Texturing', int), #TODO: set this based on applied texture + texturing=get_value(context, node_tree, shader_node, 'Texturing', int), #TODO: set this based on applied texture? detail_color_func=get_value(context, node_tree, shader_node, 'DetailColorFunc', int), detail_alpha_func=get_value(context, node_tree, shader_node, 'DetailAlphaFunc', int), shader_preset=get_value(context, node_tree, shader_node, 'Preset', int), @@ -72,57 +66,11 @@ def retrieve_vertex_material(context, material, shader_node): (texture, uv_map) = get_texture_value(context, node_tree, shader_node, 'DiffuseTexture') - texture_struct = Texture(file=texture) - tx_coords = - - - #return vert_mat, shader, texture_struct, tx_coords, pass_index, prelit_type - return vert_mat + return (vert_mat, shader, texture, uv_map) -def append_property(shader_mat, type, name, value, default=None): - if value is None: - return - if type == 1: - if isinstance(value, str): - if value == '': # default - return - elif value.image is None: - return - else: - value = value.image.name - elif type == 2: - if default is None: - default = 0.0 - if abs(value - default) < 0.01: - return - elif type == 3 and default is None: - default = Vector().xy - elif type == 4 and default is None: - default = Vector() - elif type == 5 and default is None: - default = Vector((0.0, 0.0, 0.0, 1.0)) - elif type == 6 and default is None: - default = 0 - elif type == 7 and default is None: - default = False - - if value == default: - return - shader_mat.properties.append(ShaderMaterialProperty( - type=type, name=name, value=value)) - - -def to_vec(color): - return Vector((color[0], color[1], color[2], color[3] if len(color) > 3 else 1.0)) - - -def retrieve_shader_material(context, material, principled, w3x=False): - name = material.name.split('.', 1)[-1] - if not name.endswith('.fx'): - context.info(name + ' is not a valid shader name -> defaulting to: DefaultW3D.fx') - name = 'DefaultW3D.fx' - +def retrieve_shader_material(context, material, shader_node): + name = shader_node.node_tree.name shader_mat = ShaderMaterial( header=ShaderMaterialHeader( type_name=name), @@ -130,86 +78,39 @@ def retrieve_shader_material(context, material, principled, w3x=False): shader_mat.header.technique_index = material.technique - if w3x: - append_property(shader_mat, 2, 'Shininess', material.specular_intensity * 200.0, 100.0) - append_property(shader_mat, 5, 'ColorDiffuse', to_vec(material.diffuse_color), Vector((0.8, 0.8, 0.8, 1.0))) - append_property(shader_mat, 5, 'ColorSpecular', to_vec(material.specular_color), Vector((1.0, 1.0, 1.0, 1.0))) - append_property(shader_mat, 5, 'ColorAmbient', to_vec(material.ambient), Vector((1.0, 1.0, 1.0, 0.0))) - append_property(shader_mat, 5, 'ColorEmissive', to_vec(material.emission), Vector((1.0, 1.0, 1.0, 0.0))) - - else: - append_property(shader_mat, 2, 'SpecularExponent', material.specular_intensity * 200.0, 100.0) - append_property(shader_mat, 5, 'DiffuseColor', to_vec(material.diffuse_color), Vector((0.8, 0.8, 0.8, 1.0))) - append_property(shader_mat, 5, 'SpecularColor', to_vec(material.specular_color), Vector((1.0, 1.0, 1.0, 1.0))) - append_property(shader_mat, 5, 'AmbientColor', to_vec(material.ambient), Vector((1.0, 1.0, 1.0, 0.0))) - append_property(shader_mat, 5, 'EmissiveColor', to_vec(material.emission), Vector((1.0, 1.0, 1.0, 0.0))) - - if material.texture_1: - append_property(shader_mat, 1, 'Texture_0', principled.base_color_texture) - append_property(shader_mat, 1, 'Texture_1', material.texture_1) - append_property(shader_mat, 6, 'NumTextures', 2) - append_property(shader_mat, 6, 'SecondaryTextureBlendMode', material.secondary_texture_blend_mode) - append_property(shader_mat, 6, 'TexCoordMapper_0', material.tex_coord_mapper_0) - append_property(shader_mat, 6, 'TexCoordMapper_1', material.tex_coord_mapper_1) - append_property(shader_mat, 5, 'TexCoordTransform_0', to_vec(material.tex_coord_transform_0), Vector()) - append_property(shader_mat, 5, 'TexCoordTransform_1', to_vec(material.tex_coord_transform_1), Vector()) - else: - append_property(shader_mat, 1, 'DiffuseTexture', principled.base_color_texture) - - append_property(shader_mat, 1, 'NormalMap', principled.normalmap_texture) - if principled.normalmap_texture is not None and principled.normalmap_texture.image is not None: - if shader_mat.header.type_name == 'DefaultW3D.fx': - shader_mat.header.type_name = 'NormalMapped.fx' - append_property(shader_mat, 2, 'BumpScale', principled.normalmap_strength, 1.0) - - append_property(shader_mat, 1, 'SpecMap', principled.specular_texture) - append_property(shader_mat, 7, 'CullingEnable', material.use_backface_culling) - append_property(shader_mat, 2, 'Opacity', material.opacity) - append_property(shader_mat, 7, 'AlphaTestEnable', material.alpha_test, True) - append_property(shader_mat, 6, 'BlendMode', material.blend_mode) - append_property(shader_mat, 3, 'BumpUVScale', material.bump_uv_scale) - append_property(shader_mat, 6, 'EdgeFadeOut', material.edge_fade_out) - append_property(shader_mat, 7, 'DepthWriteEnable', material.depth_write) - append_property(shader_mat, 5, 'Sampler_ClampU_ClampV_NoMip_0', - material.sampler_clamp_uv_no_mip_0, Vector((0.0, 0.0, 0.0, 0.0))) - append_property(shader_mat, 5, 'Sampler_ClampU_ClampV_NoMip_1', - material.sampler_clamp_uv_no_mip_1, Vector((0.0, 0.0, 0.0, 0.0))) - append_property(shader_mat, 1, 'EnvironmentTexture', material.environment_texture) - append_property(shader_mat, 2, 'EnvMult', material.environment_mult) - append_property(shader_mat, 1, 'RecolorTexture', material.recolor_texture) - append_property(shader_mat, 2, 'RecolorMultiplier', material.recolor_mult) - append_property(shader_mat, 7, 'UseRecolorColors', material.use_recolor) - append_property(shader_mat, 7, 'HouseColorPulse', material.house_color_pulse) - append_property(shader_mat, 1, 'ScrollingMaskTexture', material.scrolling_mask_texture) - append_property(shader_mat, 2, 'TexCoordTransformAngle_0', material.tex_coord_transform_angle) - append_property(shader_mat, 2, 'TexCoordTransformU_0', material.tex_coord_transform_u_0) - append_property(shader_mat, 2, 'TexCoordTransformV_0', material.tex_coord_transform_v_0) - append_property(shader_mat, 2, 'TexCoordTransformU_1', material.tex_coord_transform_u_1) - append_property(shader_mat, 2, 'TexCoordTransformV_1', material.tex_coord_transform_v_1) - append_property(shader_mat, 2, 'TexCoordTransformU_2', material.tex_coord_transform_u_2) - append_property(shader_mat, 2, 'TexCoordTransformV_2', material.tex_coord_transform_v_2) - append_property(shader_mat, 5, 'TextureAnimation_FPS_NumPerRow_LastFrame_FrameOffset_0', - material.tex_ani_fps_NPR_lastFrame_frameOffset_0, Vector((0.0, 0.0, 0.0, 0.0))) - append_property(shader_mat, 1, 'IonHullTexture', material.ion_hull_texture) - append_property(shader_mat, 7, 'MultiTextureEnable', material.multi_texture_enable) + filename = name.replace('.fx', '.xml') + input_types_dict = get_group_input_types(filename) + node_tree = material.node_tree - return shader_mat + uv_map = None + + for input in shader_node.inputs: + if input.identifier in input_types_dict: + (type, default) = input_types_dict[input.identifier] + if type == 'ShaderNodeTexture': + (texture, uv_map) = get_texture_value(context, node_tree, input) + if texture is not None: + shader_mat.properties.append(ShaderMaterialProperty( + type=STRING_PROPERTY, + name=input.identifier, + value=texture)) + + elif type == 'ShaderNodeFloat': + value = get_value(context, node_tree, input) + default = child_node.get('default', 0.0) + elif type == 'ShaderNodeVector2': + default = child_node.get('default', Vector((0.0, 0.0))) + elif type == 'ShaderNodeVector': + default = child_node.get('default', Vector((0.0, 0.0, 0.0))) + elif type == 'ShaderNodeVector4': + default = child_node.get('default', Vector((0.0, 0.0, 0.0, 0.0))) + elif type == 'ShaderNodeInt': + default = child_node.get('default', 0) + elif type == 'ShaderNodeByte': + default = child_node.get('default', 0) + append_property(shader_mat, type, input.identifier, input.) + else: + context.warning('node group input ' + input.identifier + ' is not defined in ' + filename) + return shader_mat -def retrieve_shader(material): - return Shader( - depth_compare=material.shader.depth_compare, - depth_mask=material.shader.depth_mask, - color_mask=material.shader.color_mask, - dest_blend=material.shader.dest_blend, - fog_func=material.shader.fog_func, - pri_gradient=material.shader.pri_gradient, - sec_gradient=material.shader.sec_gradient, - src_blend=material.shader.src_blend, - texturing=material.shader.texturing, - detail_color_func=material.shader.detail_color_func, - detail_alpha_func=material.shader.detail_alpha_func, - shader_preset=material.shader.shader_preset, - alpha_test=material.shader.alpha_test, - post_detail_color_func=material.shader.post_detail_color_func, - post_detail_alpha_func=material.shader.post_detail_alpha_func) diff --git a/io_mesh_w3d/common/utils/mesh_export.py b/io_mesh_w3d/common/utils/mesh_export.py index fd7da1a3..b6058a2e 100644 --- a/io_mesh_w3d/common/utils/mesh_export.py +++ b/io_mesh_w3d/common/utils/mesh_export.py @@ -132,17 +132,15 @@ def retrieve_meshes(context, hierarchy, rig, container_name, force_vertex_materi header.sphCenter = center header.sphRadius = radius - tx_stages = [] - for i, uv_layer in enumerate(mesh.uv_layers): - stage = TextureStage( - tx_ids=[i], - tx_coords=[Vector((0.0, 0.0))] * len(mesh_struct.verts)) + tx_coord_dict = {} + for uv_layer in mesh.uv_layers: + tx_coords=[None] * len(mesh_struct.verts) for j, face in enumerate(b_mesh.faces): for loop in face.loops: vert_index = mesh_struct.triangles[j].vert_ids[loop.index % 3] - stage.tx_coords[vert_index] = uv_layer.data[loop.index].uv.copy() - tx_stages.append(stage) + tx_coords[vert_index] = uv_layer.data[loop.index].uv.copy() + tx_coord_dict[uv_layer.name] = tx_coords b_mesh.free() diff --git a/io_mesh_w3d/common/utils/node_group_creator.py b/io_mesh_w3d/common/utils/node_group_creator.py index 0ebc3931..99081136 100644 --- a/io_mesh_w3d/common/utils/node_group_creator.py +++ b/io_mesh_w3d/common/utils/node_group_creator.py @@ -70,7 +70,6 @@ def create_input_node(self, node_tree, xml_node, node): continue type = child_node.get('type') name = child_node.get('name') - shape = 'CIRCLE' if type == 'NodeSocketTexture': type = 'NodeSocketColor' From 7adc8cad0e5ff57764900eed573fcc8c6c6bebc4 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Thu, 9 Apr 2020 19:59:41 +0200 Subject: [PATCH 39/62] got shader material roundtrip somewhat working again, first work on vertex material combinations --- io_mesh_w3d/common/utils/helpers.py | 76 ++++++------ io_mesh_w3d/common/utils/material_export.py | 115 ++++++++++-------- io_mesh_w3d/common/utils/material_import.py | 35 ++++-- .../common/utils/node_group_creator.py | 9 ++ .../node_group_templates/NormalMapped.xml | 8 +- 5 files changed, 138 insertions(+), 105 deletions(-) diff --git a/io_mesh_w3d/common/utils/helpers.py b/io_mesh_w3d/common/utils/helpers.py index 4522e9e4..6686cfdb 100644 --- a/io_mesh_w3d/common/utils/helpers.py +++ b/io_mesh_w3d/common/utils/helpers.py @@ -3,8 +3,10 @@ import bpy import os +from os.path import dirname as up from mathutils import Quaternion, Matrix from bpy_extras.image_utils import load_image +from io_mesh_w3d.common.io_xml import find_root from io_mesh_w3d.common.structs.rgba import RGBA @@ -130,59 +132,59 @@ def find_texture(context, file, name=None): return img -def get_color_value(context, node_tree, node, input): +def get_vec_value(context, node_tree, socket): + for link in socket.links: + return link.from_node.outputs['Vector'].default_value + return socket.default_value + + +def get_vec2_value(context, node_tree, socket): + return get_vec_value(context, node_tree, socket).xy + + +def get_color_value(context, node_tree, socket): type = 'ShaderNodeRGB' - socket = node.inputs[input] - if not socket.is_linked: - return RGBA(vec=socket.default_value) + for link in socket.links: if link.from_node.bl_idname == type: return RGBA(vec=link.from_node.outputs['Color'].default_value) else: - context.error('Node ' + link.from_node.bl_idname + ' connected to ' + input + ' in ' + node_tree.name + ' is not of type ' + type) - return RGBA() + context.error('Node ' + link.from_node.bl_idname + ' connected to ' + socket.name + ' in ' + node_tree.name + ' is not of type ' + type) + return RGBA(vec=socket.default_value) -def get_uv_value(context, node_tree, node, input): +def get_uv_value(context, node_tree, socket): type = 'ShaderNodeUVMap' - socket = node.inputs[input] - if not socket.is_linked: - return None + for link in socket.links: if link.from_node.bl_idname == type: return link.from_node.uv_map else: - context.error('Node ' + link.from_node.bl_idname + ' connected to ' + input + ' in ' + node_tree.name + ' is not of type ' + type) + context.error('Node ' + link.from_node.bl_idname + ' connected to ' + socket.name + ' in ' + node_tree.name + ' is not of type ' + type) return None + def get_texture_value(context, node_tree, socket): type = 'ShaderNodeTexImage' - if not socket.is_linked: - return (None, None) + for link in socket.links: if link.from_node.bl_idname == type: - return (link.from_node.image.name, get_uv_value(context, node_tree, link.from_node, 'Vector')) + return (link.from_node.image.name, get_uv_value(context, node_tree, link.from_node.inputs['Vector'])) else: - context.error('Node ' + link.from_node.bl_idname + ' connected to ' + input + ' in ' + node_tree.name + ' is not of type ' + type) + context.error('Node ' + link.from_node.bl_idname + ' connected to ' + socket.name + ' in ' + node_tree.name + ' is not of type ' + type) return (None, None) -def get_texture_value(context, node_tree, node, input): - socket = node.inputs[input] - return get_texture_value(context, node_tree, socket) - - -def get_value(context, node_tree, node, input, cast): +def get_value(context, node_tree, socket, cast): type = 'ShaderNodeValue' - socket = node.inputs[input] - if not socket.is_linked: - return cast(socket.default_value) + for link in socket.links: if link.from_node.bl_idname == type: return cast(link.from_node.outputs['Value'].default_value) else: - context.error('Node ' + link.from_node.bl_idname + ' connected to ' + input + ' in ' + node_tree.name + ' is not of type ' + type) - return cast(0) + context.error('Node ' + link.from_node.bl_idname + ' connected to ' + socket.name + ' in ' + node_tree.name + ' is not of type ' + type) + return cast(socket.default_value) + def get_shader_node_group(context, node_tree): output_node = None @@ -205,6 +207,7 @@ def get_shader_node_group(context, node_tree): # TODO: handle the default PrincipledBSDF here return None + def get_group_input_types(filename): dirname = os.path.dirname(__file__) directory = os.path.join(up(up(dirname)), 'node_group_templates') @@ -218,7 +221,6 @@ def get_group_input_types(filename): if name.replace('.fx', '') != filename.replace('.xml', ''): return {} - links = node_tree.links inputs = {} for xml_node in root: @@ -226,8 +228,8 @@ def get_group_input_types(filename): parent = xml_node.get('file') inputs = get_group_input_types(parent) elif xml_node.tag == 'node': - type = xml_node.get('type') - if type != 'NodeGroupInput': + node_type = xml_node.get('type') + if node_type != 'NodeGroupInput': continue for child_node in xml_node: @@ -235,19 +237,19 @@ def get_group_input_types(filename): continue type = child_node.get('type') - if type == 'ShaderNodeTexture': + if type == 'NodeSocketTexture': default = child_node.get('default', None) - elif type == 'ShaderNodeFloat': + elif type == 'NodeSocketColor': + default = child_node.get('default', RGBA()) + elif type == 'NodeSocketFloat': default = child_node.get('default', 0.0) - elif type == 'ShaderNodeVector2': + elif type == 'NodeSocketVector2': default = child_node.get('default', Vector((0.0, 0.0))) - elif type == 'ShaderNodeVector': + elif type == 'NodeSocketVector': default = child_node.get('default', Vector((0.0, 0.0, 0.0))) - elif type == 'ShaderNodeVector4': + elif type == 'NodeSocketVector4': default = child_node.get('default', Vector((0.0, 0.0, 0.0, 0.0))) - elif type == 'ShaderNodeInt': - default = child_node.get('default', 0) - elif type == 'ShaderNodeByte': + elif type in ['NodeSocketInt', 'NodeSocketByte']: default = child_node.get('default', 0) inputs[child_node.get('name')] = (type, default) diff --git a/io_mesh_w3d/common/utils/material_export.py b/io_mesh_w3d/common/utils/material_export.py index 4ea6a349..ca8c5db1 100644 --- a/io_mesh_w3d/common/utils/material_export.py +++ b/io_mesh_w3d/common/utils/material_export.py @@ -15,7 +15,8 @@ def retrieve_material(context, material): if shader_node.node_tree.name in vertex_materials_ids: retrieve_vertex_material(context, material, shader_node) - # else: shader material + else: + retrieve_shader_material(context, material, shader_node) def retrieve_vertex_material(context, material, shader_node): @@ -24,12 +25,12 @@ def retrieve_vertex_material(context, material, shader_node): info = VertexMaterialInfo( attributes=0, shininess=material.specular_intensity, - specular=get_color_value(context, node_tree, shader_node, 'Specular'), - diffuse=get_color_value(context, node_tree, shader_node, 'Diffuse'), - emissive=get_color_value(context, node_tree, shader_node, 'Emissive'), - ambient=get_color_value(context, node_tree, shader_node, 'Ambient'), - translucency=get_value(context, node_tree, shader_node, 'Translucency', float), - opacity=get_value(context, node_tree, shader_node, 'Opacity', float)) + specular=get_color_value(context, node_tree, shader_node.inputs['Specular']), + diffuse=get_color_value(context, node_tree, shader_node.inputs['Diffuse']), + emissive=get_color_value(context, node_tree, shader_node.inputs['Emissive']), + ambient=get_color_value(context, node_tree, shader_node.inputs['Ambient']), + translucency=get_value(context, node_tree, shader_node.inputs['Translucency'], float), + opacity=get_value(context, node_tree, shader_node.inputs['Opacity'], float)) if 'USE_DEPTH_CUE' in material.attributes: info.attributes |= USE_DEPTH_CUE @@ -48,69 +49,75 @@ def retrieve_vertex_material(context, material, shader_node): vert_mat.vm_args_1 = material.vm_args_1 shader = Shader( - depth_compare=get_value(context, node_tree, shader_node, 'DepthCompare', int), - depth_mask=get_value(context, node_tree, shader_node, 'DepthMask', int), - color_mask=get_value(context, node_tree, shader_node, 'ColorMask', int), - dest_blend=get_value(context, node_tree, shader_node, 'DestBlend', int), - fog_func=get_value(context, node_tree, shader_node, 'FogFunc', int), - pri_gradient=get_value(context, node_tree, shader_node, 'PriGradient', int), - sec_gradient=get_value(context, node_tree, shader_node, 'SecGradient', int), - src_blend=get_value(context, node_tree, shader_node, 'SrcBlend', int), - texturing=get_value(context, node_tree, shader_node, 'Texturing', int), #TODO: set this based on applied texture? - detail_color_func=get_value(context, node_tree, shader_node, 'DetailColorFunc', int), - detail_alpha_func=get_value(context, node_tree, shader_node, 'DetailAlphaFunc', int), - shader_preset=get_value(context, node_tree, shader_node, 'Preset', int), - alpha_test=get_value(context, node_tree, shader_node, 'AlphaTest', int), - post_detail_color_func=get_value(context, node_tree, shader_node, 'PostDetailColorFunc', int), - post_detail_alpha_func=get_value(context, node_tree, shader_node, 'PostDetailAlphaFunc', int)) - - (texture, uv_map) = get_texture_value(context, node_tree, shader_node, 'DiffuseTexture') + depth_compare=get_value(context, node_tree, shader_node.inputs['DepthCompare'], int), + depth_mask=get_value(context, node_tree, shader_node.inputs['DepthMask'], int), + color_mask=get_value(context, node_tree, shader_node.inputs['ColorMask'], int), + dest_blend=get_value(context, node_tree, shader_node.inputs['DestBlend'], int), + fog_func=get_value(context, node_tree, shader_node.inputs['FogFunc'], int), + pri_gradient=get_value(context, node_tree, shader_node.inputs['PriGradient'], int), + sec_gradient=get_value(context, node_tree, shader_node.inputs['SecGradient'], int), + src_blend=get_value(context, node_tree, shader_node.inputs['SrcBlend'], int), + texturing=get_value(context, node_tree, shader_node.inputs['Texturing'], int), #TODO: set this based on applied texture? + detail_color_func=get_value(context, node_tree, shader_node.inputs['DetailColorFunc'], int), + detail_alpha_func=get_value(context, node_tree, shader_node.inputs['DetailAlphaFunc'], int), + shader_preset=get_value(context, node_tree, shader_node.inputs['Preset'], int), + alpha_test=get_value(context, node_tree, shader_node.inputs['AlphaTest'], int), + post_detail_color_func=get_value(context, node_tree, shader_node.inputs['PostDetailColorFunc'], int), + post_detail_alpha_func=get_value(context, node_tree, shader_node.inputs['PostDetailAlphaFunc'], int)) + + (texture, uv_map) = get_texture_value(context, node_tree, shader_node.inputs['DiffuseTexture']) return (vert_mat, shader, texture, uv_map) def retrieve_shader_material(context, material, shader_node): - name = shader_node.node_tree.name + node_tree = shader_node.node_tree + name = node_tree.name shader_mat = ShaderMaterial( header=ShaderMaterialHeader( type_name=name), properties=[]) - shader_mat.header.technique_index = material.technique - + shader_mat.header.technique_index = get_value(context, node_tree, shader_node.inputs['Technique'], int) + filename = name.replace('.fx', '.xml') input_types_dict = get_group_input_types(filename) - node_tree = material.node_tree uv_map = None for input in shader_node.inputs: - if input.identifier in input_types_dict: - (type, default) = input_types_dict[input.identifier] - if type == 'ShaderNodeTexture': - (texture, uv_map) = get_texture_value(context, node_tree, input) - if texture is not None: - shader_mat.properties.append(ShaderMaterialProperty( - type=STRING_PROPERTY, - name=input.identifier, - value=texture)) - - elif type == 'ShaderNodeFloat': - value = get_value(context, node_tree, input) - default = child_node.get('default', 0.0) - elif type == 'ShaderNodeVector2': - default = child_node.get('default', Vector((0.0, 0.0))) - elif type == 'ShaderNodeVector': - default = child_node.get('default', Vector((0.0, 0.0, 0.0))) - elif type == 'ShaderNodeVector4': - default = child_node.get('default', Vector((0.0, 0.0, 0.0, 0.0))) - elif type == 'ShaderNodeInt': - default = child_node.get('default', 0) - elif type == 'ShaderNodeByte': - default = child_node.get('default', 0) - append_property(shader_mat, type, input.identifier, input.) + if input.name in input_types_dict: + (type, default) = input_types_dict[input.name] + + if type == 'NodeSocketTexture': + prop_type = STRING_PROPERTY + (value, uv_map) = get_texture_value(context, node_tree, input) + elif type == 'NodeSocketTextureAlpha': + continue + elif type == 'NodeSocketFloat': + prop_type = FLOAT_PROPERTY + value = get_value(context, node_tree, input, float) + elif type == 'NodeSocketVector2': + prop_type = VEC2_PROPERTY + value = get_vec2_value(context, node_tree, input) + elif type == 'NodeSocketVector': + prop_type = VEC3_PROPERTY + value = get_vec_value(context, node_tree, input) + elif type in ['NodeSocketVector4', 'NodeSocketColor']: + prop_type = VEC4_PROPERTY + value = get_color_value(context, node_tree, input) + elif type == 'NodeSocketInt': + prop_type = LONG_PROPERTY + value = get_value(context, node_tree, input, int) + elif type == 'NodeSocketByte': + prop_type = BYTE_PROPERTY + value = get_value(context, node_tree, input, int) + else: + context.warning('Invalid node socket type: ' + type + ' !') + if value != default: + shader_mat.properties.append(ShaderMaterialProperty(type=prop_type, name=input.name, value=value)) else: - context.warning('node group input ' + input.identifier + ' is not defined in ' + filename) + context.warning('node group input ' + input.name + ' is not defined in ' + filename) - return shader_mat + return (shader_mat, uv_map) diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index 9503c4c6..d0c45c52 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -31,18 +31,24 @@ def get_or_create_uv_layer(mesh, b_mesh, triangles, tx_coords): return uv_layer.name -def create_materials_from_combinations(mesh, vert_mat_ids, shader_ids, tex_ids): - materials = {} +def expand_indices(indices, count): + if len(indices) == 0: + return [indices[0]] * count + return indices - if len(vert_mat_ids) == 0: - vert_mat_ids = [vert_mat_ids[0]] * len(mesh.vertices) - if len(shader_ids) == 0: - shader_ids = [shader_ids[0]] * len(mesh.vertices) - if len(tex_ids) == 0: - tex_ids = [tex_ids[0]] * len(tex_ids) - # TODO - #for i, vertex in enumerate(mesh.vertices): +def create_vertex_material_combinations(count, mat_pass): + vert_mat_ids = expand_indices(mat_pass.vertex_material_ids, count) + shader_ids = expand_indices(mat_pass.shader_ids, count) + tex_ids = expand_indices(tex_ids, count) + + combinations = [] + unique_combinations = set() + for i in range(count): + combination = (vert_mat_ids[i], shader_ids[i], tex_ids[i]) + combinations.append(combination) + unique_combinations.add(combination) + return (combinations, unique_combinations) @@ -57,12 +63,16 @@ def create_material_passes(context, base_struct, mesh, triangles): shader_materials = [] tx_coords = [] + + (combinations, unique_combinations) = create_vertex_material_combinations(len(mesh.vertices), mat_pass) + for vert_mat_id in mat_pass.vertex_material_ids: vert_materials.append(base_struct.vert_materials[vert_mat_id]) for shader_id in mat_pass.shader_ids: shaders.append(base_struct.shaders[shader_id]) + # do we also take multiple texture stages into account for tx_stage in mat_pass.tx_stages: textures.append(base_struct.textures[tx_stage.tx_ids[0]]) tx_coords.append(tx_stage.tx_coords) @@ -116,6 +126,11 @@ def create_vertex_material(context, mesh, b_mesh, triangles, vert_mat, shader, t material.attributes.add('DEPTH_CUE_TO_ALPHA') # TODO: translate those to shader properties + # floats: UPerSec, VPerSec, UScale, VScale, FPS, Speed, UCenter, VCenter, UAmp, UFreq, UPhase, VAmp, VFreq, VPhase, + # UStep, VStep, StepsPerSecond, Offset, Axis, UOffset, VOffset, ClampFix, UseReflect, Period, VPerScale, + # BumpRotation, BumpScale + # ints: Log1Width, Log2Width, Last(Frame) + material.vm_args_0 = vert_mat.vm_args_0 material.vm_args_1 = vert_mat.vm_args_1 diff --git a/io_mesh_w3d/common/utils/node_group_creator.py b/io_mesh_w3d/common/utils/node_group_creator.py index 99081136..139175af 100644 --- a/io_mesh_w3d/common/utils/node_group_creator.py +++ b/io_mesh_w3d/common/utils/node_group_creator.py @@ -71,8 +71,17 @@ def create_input_node(self, node_tree, xml_node, node): type = child_node.get('type') name = child_node.get('name') + # those special types are needed for export functionality only if type == 'NodeSocketTexture': type = 'NodeSocketColor' + elif type == 'NodeSocketTextureAlpha': + type = 'NodeSocketFloat' + elif type == 'NodeSocketVector2': + type = 'NodeSocketVector' + elif type == 'NodeSocketVector4': + type = 'NodeSocketColor' + elif type == 'NodeSocketByte': + type = 'NodeSocketInt' socket = node_tree.inputs.new(type, name) self.process_presets(socket, child_node, name) diff --git a/io_mesh_w3d/node_group_templates/NormalMapped.xml b/io_mesh_w3d/node_group_templates/NormalMapped.xml index 864f1b51..f673d15b 100644 --- a/io_mesh_w3d/node_group_templates/NormalMapped.xml +++ b/io_mesh_w3d/node_group_templates/NormalMapped.xml @@ -4,11 +4,11 @@ - - + + - - + + From 526c44f5d27c3bffb2591e69df73478b2d023e43 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Sat, 11 Apr 2020 19:31:22 +0200 Subject: [PATCH 40/62] more work on material stuff --- io_mesh_w3d/common/structs/rgba.py | 3 + io_mesh_w3d/common/utils/helpers.py | 15 +-- io_mesh_w3d/common/utils/material_export.py | 44 +++++-- io_mesh_w3d/common/utils/material_import.py | 117 ++++-------------- io_mesh_w3d/common/utils/mesh_export.py | 25 +--- io_mesh_w3d/common/utils/mesh_import.py | 2 +- io_mesh_w3d/node_group_templates/BasicW3D.xml | 2 +- .../node_group_templates/DefaultW3D.xml | 8 +- io_mesh_w3d/node_group_templates/Infantry.xml | 4 +- .../node_group_templates/MuzzleFlash.xml | 3 +- .../node_group_templates/ObjectsAlien.xml | 4 +- .../node_group_templates/ObjectsGDI.xml | 8 +- .../node_group_templates/ObjectsNOD.xml | 8 +- .../w3d/structs/mesh_structs/shader.py | 8 ++ version_history.txt | 5 + 15 files changed, 103 insertions(+), 153 deletions(-) diff --git a/io_mesh_w3d/common/structs/rgba.py b/io_mesh_w3d/common/structs/rgba.py index ee0039bd..d1be379d 100644 --- a/io_mesh_w3d/common/structs/rgba.py +++ b/io_mesh_w3d/common/structs/rgba.py @@ -67,6 +67,9 @@ def __eq__(self, other): return self.r == other.r and self.g == other.g and self.b == other.b and self.a == other.a return False + def __ne__(self, other): + return not self.__eq__(other) + def __str__(self): return 'RGBA(r:' + str(self.r) + ', g:' + str(self.g) + \ ', b:' + str(self.b) + ', a:' + str(self.a) + ')' diff --git a/io_mesh_w3d/common/utils/helpers.py b/io_mesh_w3d/common/utils/helpers.py index 6686cfdb..a4b1466a 100644 --- a/io_mesh_w3d/common/utils/helpers.py +++ b/io_mesh_w3d/common/utils/helpers.py @@ -153,26 +153,15 @@ def get_color_value(context, node_tree, socket): return RGBA(vec=socket.default_value) -def get_uv_value(context, node_tree, socket): - type = 'ShaderNodeUVMap' - - for link in socket.links: - if link.from_node.bl_idname == type: - return link.from_node.uv_map - else: - context.error('Node ' + link.from_node.bl_idname + ' connected to ' + socket.name + ' in ' + node_tree.name + ' is not of type ' + type) - return None - - def get_texture_value(context, node_tree, socket): type = 'ShaderNodeTexImage' for link in socket.links: if link.from_node.bl_idname == type: - return (link.from_node.image.name, get_uv_value(context, node_tree, link.from_node.inputs['Vector'])) + return link.from_node.image.name else: context.error('Node ' + link.from_node.bl_idname + ' connected to ' + socket.name + ' in ' + node_tree.name + ' is not of type ' + type) - return (None, None) + return None def get_value(context, node_tree, socket, cast): diff --git a/io_mesh_w3d/common/utils/material_export.py b/io_mesh_w3d/common/utils/material_export.py index ca8c5db1..a04f52f0 100644 --- a/io_mesh_w3d/common/utils/material_export.py +++ b/io_mesh_w3d/common/utils/material_export.py @@ -4,19 +4,40 @@ from mathutils import Vector from io_mesh_w3d.w3d.structs.mesh_structs.shader import * from io_mesh_w3d.w3d.structs.mesh_structs.vertex_material import * +from io_mesh_w3d.w3d.structs.mesh_structs.material_pass import * +from io_mesh_w3d.common.structs.mesh_structs.texture import * from io_mesh_w3d.common.structs.mesh_structs.shader_material import * -def retrieve_material(context, material): - vertex_materials_ids = [VertexMaterialGroup.name, PrelitUnlitGroup.name, PrelitVertexGroup.name, - PrelitLightmapMultiPassGroup.name, PrelitLightmapMultiTextureGroup.name] - +def retrieve_material(context, mesh, material, tx_coords): shader_node = get_shader_node_group(context, material.node_tree) - if shader_node.node_tree.name in vertex_materials_ids: - retrieve_vertex_material(context, material, shader_node) + if shader_node.node_tree.name == VertexMaterialGroup.name: + (vert_mat, shader, tex_name) = retrieve_vertex_material(context, material, shader_node) + mesh.vertex_materials = [vert_mat] + mesh.shaders = [shader] + mesh.textures = [Texture(file=tex_name, info=None)] + + tx_stage = TextureStage( + tx_ids=[0], + tx_coords=tx_coords) + + mesh.material_passes.append(MaterialPass( + vertex_material_ids=[0], + shader_ids=[0], + shader_material_ids=[], + tx_stages=[tx_stage], + tx_coords=[])) else: - retrieve_shader_material(context, material, shader_node) + shader_mat = retrieve_shader_material(context, material, shader_node) + mesh.shader_materials = [shader_mat] + + mesh.material_passes.append(MaterialPass( + vertex_material_ids=[], + shader_ids=[], + shader_material_ids=[0], + tx_stages=[], + tx_coords=tx_coords)) def retrieve_vertex_material(context, material, shader_node): @@ -44,7 +65,6 @@ def retrieve_vertex_material(context, material, shader_node): vert_mat = VertexMaterial() vert_mat.vm_name = shader_node.label vert_mat.vm_info = info - # TODO: handle these vert_mat.vm_args_0 = material.vm_args_0 vert_mat.vm_args_1 = material.vm_args_1 @@ -65,9 +85,9 @@ def retrieve_vertex_material(context, material, shader_node): post_detail_color_func=get_value(context, node_tree, shader_node.inputs['PostDetailColorFunc'], int), post_detail_alpha_func=get_value(context, node_tree, shader_node.inputs['PostDetailAlphaFunc'], int)) - (texture, uv_map) = get_texture_value(context, node_tree, shader_node.inputs['DiffuseTexture']) + texture = get_texture_value(context, node_tree, shader_node.inputs['DiffuseTexture']) - return (vert_mat, shader, texture, uv_map) + return (vert_mat, shader, texture) def retrieve_shader_material(context, material, shader_node): @@ -91,7 +111,7 @@ def retrieve_shader_material(context, material, shader_node): if type == 'NodeSocketTexture': prop_type = STRING_PROPERTY - (value, uv_map) = get_texture_value(context, node_tree, input) + value = get_texture_value(context, node_tree, input) elif type == 'NodeSocketTextureAlpha': continue elif type == 'NodeSocketFloat': @@ -119,5 +139,5 @@ def retrieve_shader_material(context, material, shader_node): else: context.warning('node group input ' + input.name + ' is not defined in ' + filename) - return (shader_mat, uv_map) + return shader_mat diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index d0c45c52..63d6d08a 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -12,107 +12,62 @@ from io_mesh_w3d.common.structs.mesh_structs.shader_material import * -def get_or_create_uv_layer(mesh, b_mesh, triangles, tx_coords): - for uv_layer in mesh.uv_layers: - layer_exists = True - for i, face in enumerate(b_mesh.faces): - for loop in face.loops: - idx = triangles[i][loop.index % 3] - if uv_layer.data[loop.index].uv != tx_coords[idx].xy: - layer_exists = False - if layer_exists: - return uv_layer.name +def create_uv_layer(mesh, b_mesh, triangles, tx_coords): + if tx_coords is None: + return uv_layer = mesh.uv_layers.new(do_init=False) for i, face in enumerate(b_mesh.faces): for loop in face.loops: idx = triangles[i][loop.index % 3] uv_layer.data[loop.index].uv = tx_coords[idx].xy - return uv_layer.name - - -def expand_indices(indices, count): - if len(indices) == 0: - return [indices[0]] * count - return indices - -def create_vertex_material_combinations(count, mat_pass): - vert_mat_ids = expand_indices(mat_pass.vertex_material_ids, count) - shader_ids = expand_indices(mat_pass.shader_ids, count) - tex_ids = expand_indices(tex_ids, count) - combinations = [] - unique_combinations = set() - for i in range(count): - combination = (vert_mat_ids[i], shader_ids[i], tex_ids[i]) - combinations.append(combination) - unique_combinations.add(combination) - return (combinations, unique_combinations) +def create_material_pass(context, base_struct, mesh, triangles): + vert_material = None + shader = None + texture = None + tx_coords = None - - -def create_material_passes(context, base_struct, mesh, triangles): b_mesh = bmesh.new() b_mesh.from_mesh(mesh) + mat_pass = base_struct.material_passes[0] - for pass_index, mat_pass in enumerate(base_struct.material_passes): - vert_materials = [] - shaders = [] - textures = [] - shader_materials = [] - tx_coords = [] - - - (combinations, unique_combinations) = create_vertex_material_combinations(len(mesh.vertices), mat_pass) + if mat_pass.vertex_material_ids: + vert_material = base_struct.vert_materials[mat_pass.vertex_material_ids[0]] - for vert_mat_id in mat_pass.vertex_material_ids: - vert_materials.append(base_struct.vert_materials[vert_mat_id]) + if mat_pass.shader_ids: + shader = base_struct.shaders[mat_pass.shader_ids[0]] - for shader_id in mat_pass.shader_ids: - shaders.append(base_struct.shaders[shader_id]) + if mat_pass.tx_stages: + tx_stage = mat_pass.tx_stages[0] + texture = base_struct.textures[tx_stage.tx_ids[0]] + tx_coords = tx_stage.tx_coords - # do we also take multiple texture stages into account - for tx_stage in mat_pass.tx_stages: - textures.append(base_struct.textures[tx_stage.tx_ids[0]]) - tx_coords.append(tx_stage.tx_coords) + if vert_material is not None and shader is not None: + create_vertex_material(context, mesh, b_mesh, triangles, vert_material, shader, texture, tx_coords) - for shader_mat_id in mat_pass.shader_material_ids: - shader_material = base_struct.shader_materials[shader_mat_id] - create_shader_material(context, mesh, b_mesh, triangles, shader_material, mat_pass.tx_coords) + if mat_pass.shader_material_ids: + shader_material = base_struct.shader_materials[0] + create_shader_material(context, mesh, b_mesh, triangles, shader_material, mat_pass.tx_coords) + b_mesh.free() - #print('vert: ' + str(len(vert_materials))) - #print('shaders: ' + str(len(shaders))) - #print('textures: ' + str(len(textures))) - #print('shader_materials: ' + str(len(shader_materials))) - #print('tx_coords: ' + str(len(tx_coords))) - - if vert_materials: - texture = None - if textures: - texture = textures[0] - tx_coordinates = None - if tx_coords: - tx_coordinates = tx_coords[0] - - #TODO: create vert_mat - shader - texture combinations - # and support different materials for each triangle - create_vertex_material(context, mesh, b_mesh, triangles, vert_materials[0], shaders[0], texture, tx_coordinates, pass_index) ########################################################################## # vertex material ########################################################################## -def create_vertex_material(context, mesh, b_mesh, triangles, vert_mat, shader, texture_struct, tx_coords, pass_index): +def create_vertex_material(context, mesh, b_mesh, triangles, vert_mat, shader, texture_struct, tx_coords): material = bpy.data.materials.new(mesh.name + '.' + vert_mat.vm_name) mesh.materials.append(material) + create_uv_layer(mesh, b_mesh, triangles, tx_coords) + material.use_nodes = True material.shadow_method = 'CLIP' material.blend_method = 'BLEND' material.show_transparent_back = False - material.pass_index = pass_index material.attributes = {'DEFAULT'} attributes = vert_mat.vm_info.attributes @@ -156,13 +111,6 @@ def create_vertex_material(context, mesh, b_mesh, triangles, vert_mat, shader, t links.new(texture_node.outputs['Color'], instance.inputs['DiffuseTexture']) links.new(texture_node.outputs['Alpha'], instance.inputs['DiffuseTextureAlpha']) - uv_layer = get_or_create_uv_layer(mesh, b_mesh, triangles, tx_coords) - - uv_node = node_tree.nodes.new('ShaderNodeUVMap') - uv_node.uv_map = uv_layer - uv_node.location = (-550, 300) - links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) - ########################################################################## # shader material @@ -171,8 +119,8 @@ def create_vertex_material(context, mesh, b_mesh, triangles, vert_mat, shader, t def create_shader_material(context, mesh, b_mesh, triangles, shader_mat, tx_coords): mat_name = shader_mat.header.type_name + create_uv_layer(mesh, b_mesh, triangles, tx_coords) - # TODO: verify that if mat_name in bpy.data.materials: mesh.materials.append(bpy.data.materials[mat_name]) return @@ -188,8 +136,6 @@ def create_shader_material(context, mesh, b_mesh, triangles, shader_mat, tx_coor node_tree.nodes.remove(node_tree.nodes.get('Principled BSDF')) - uv_layer = get_or_create_uv_layer(mesh, b_mesh, triangles, tx_coords) - instance = node_tree.nodes.new(type='ShaderNodeGroup') instance.node_tree = bpy.data.node_groups[mat_name] instance.label = mat_name @@ -201,9 +147,7 @@ def create_shader_material(context, mesh, b_mesh, triangles, shader_mat, tx_coor if shader_mat.header.technique is not None: instance.inputs['Technique'].default_value = shader_mat.header.technique - uv_node = None y = 300 - for prop in shader_mat.properties: if prop.type == STRING_PROPERTY and prop.value != '': texture_node = node_tree.nodes.new('ShaderNodeTexImage') @@ -211,17 +155,10 @@ def create_shader_material(context, mesh, b_mesh, triangles, shader_mat, tx_coor texture_node.location = (-350, y) y -= 300 - instance.inputs[prop.name].display_shape = 'SQUARE' - links.new(texture_node.outputs['Color'], instance.inputs[prop.name]) index = instance.inputs.keys().index(prop.name) links.new(texture_node.outputs['Alpha'], instance.inputs[index + 1]) - if uv_node is None: - uv_node = node_tree.nodes.new('ShaderNodeUVMap') - uv_node.uv_map = uv_layer - uv_node.location = (-600, 300) - links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) elif prop.type == VEC4_PROPERTY: instance.inputs[prop.name].default_value = prop.to_rgba() else: diff --git a/io_mesh_w3d/common/utils/mesh_export.py b/io_mesh_w3d/common/utils/mesh_export.py index b6058a2e..573a0a11 100644 --- a/io_mesh_w3d/common/utils/mesh_export.py +++ b/io_mesh_w3d/common/utils/mesh_export.py @@ -132,28 +132,15 @@ def retrieve_meshes(context, hierarchy, rig, container_name, force_vertex_materi header.sphCenter = center header.sphRadius = radius - tx_coord_dict = {} - for uv_layer in mesh.uv_layers: - tx_coords=[None] * len(mesh_struct.verts) - - for j, face in enumerate(b_mesh.faces): - for loop in face.loops: - vert_index = mesh_struct.triangles[j].vert_ids[loop.index % 3] - tx_coords[vert_index] = uv_layer.data[loop.index].uv.copy() - tx_coord_dict[uv_layer.name] = tx_coords + tx_coords = [None] * len(mesh_struct.verts) + for j, face in enumerate(b_mesh.faces): + for loop in face.loops: + vert_index = mesh_struct.triangles[j].vert_ids[loop.index % 3] + tx_coords[vert_index] = mesh.uv_layers[0].data[loop.index].uv.copy() b_mesh.free() - for i, material in enumerate(mesh.materials): - mat_pass = MaterialPass() - - #principled = node_shader_utils.PrincipledBSDFWrapper(material, is_readonly=True) - - #used_textures = get_used_textures(material, principled, used_textures) - - retrieve_material(context, material) - - + retrieve_material(context, mesh_struct, mesh.materials[0], tx_coords) header.vert_channel_flags = VERTEX_CHANNEL_LOCATION | VERTEX_CHANNEL_NORMAL diff --git a/io_mesh_w3d/common/utils/mesh_import.py b/io_mesh_w3d/common/utils/mesh_import.py index 45cfc241..30238c7e 100644 --- a/io_mesh_w3d/common/utils/mesh_import.py +++ b/io_mesh_w3d/common/utils/mesh_import.py @@ -30,7 +30,7 @@ def create_mesh(context, mesh_struct, coll): if mesh_struct.is_hidden(): mesh_ob.hide_set(True) - create_material_passes(context, mesh_struct, mesh, triangles) + create_material_pass(context, mesh_struct, mesh, triangles) def rig_mesh(mesh_struct, hierarchy, rig, sub_object=None): diff --git a/io_mesh_w3d/node_group_templates/BasicW3D.xml b/io_mesh_w3d/node_group_templates/BasicW3D.xml index c498c46d..1c25cb86 100644 --- a/io_mesh_w3d/node_group_templates/BasicW3D.xml +++ b/io_mesh_w3d/node_group_templates/BasicW3D.xml @@ -5,7 +5,7 @@ - + diff --git a/io_mesh_w3d/node_group_templates/DefaultW3D.xml b/io_mesh_w3d/node_group_templates/DefaultW3D.xml index 92f8e9c4..4fec0937 100644 --- a/io_mesh_w3d/node_group_templates/DefaultW3D.xml +++ b/io_mesh_w3d/node_group_templates/DefaultW3D.xml @@ -4,10 +4,10 @@ - - - - + + + + diff --git a/io_mesh_w3d/node_group_templates/Infantry.xml b/io_mesh_w3d/node_group_templates/Infantry.xml index a26d534c..e24ac077 100644 --- a/io_mesh_w3d/node_group_templates/Infantry.xml +++ b/io_mesh_w3d/node_group_templates/Infantry.xml @@ -4,8 +4,8 @@ - - + + diff --git a/io_mesh_w3d/node_group_templates/MuzzleFlash.xml b/io_mesh_w3d/node_group_templates/MuzzleFlash.xml index c49de3aa..a9d04fdb 100644 --- a/io_mesh_w3d/node_group_templates/MuzzleFlash.xml +++ b/io_mesh_w3d/node_group_templates/MuzzleFlash.xml @@ -3,7 +3,8 @@ - + + diff --git a/io_mesh_w3d/node_group_templates/ObjectsAlien.xml b/io_mesh_w3d/node_group_templates/ObjectsAlien.xml index c50bac2e..5ae27c34 100644 --- a/io_mesh_w3d/node_group_templates/ObjectsAlien.xml +++ b/io_mesh_w3d/node_group_templates/ObjectsAlien.xml @@ -2,7 +2,7 @@ - - + + diff --git a/io_mesh_w3d/node_group_templates/ObjectsGDI.xml b/io_mesh_w3d/node_group_templates/ObjectsGDI.xml index d3a16a23..4fe331e4 100644 --- a/io_mesh_w3d/node_group_templates/ObjectsGDI.xml +++ b/io_mesh_w3d/node_group_templates/ObjectsGDI.xml @@ -2,10 +2,10 @@ - - - - + + + + diff --git a/io_mesh_w3d/node_group_templates/ObjectsNOD.xml b/io_mesh_w3d/node_group_templates/ObjectsNOD.xml index 0ee96077..74c261bb 100644 --- a/io_mesh_w3d/node_group_templates/ObjectsNOD.xml +++ b/io_mesh_w3d/node_group_templates/ObjectsNOD.xml @@ -2,10 +2,10 @@ - - - - + + + + diff --git a/io_mesh_w3d/w3d/structs/mesh_structs/shader.py b/io_mesh_w3d/w3d/structs/mesh_structs/shader.py index 3541d95a..0001e993 100644 --- a/io_mesh_w3d/w3d/structs/mesh_structs/shader.py +++ b/io_mesh_w3d/w3d/structs/mesh_structs/shader.py @@ -68,3 +68,11 @@ def write(self, io_stream): write_ubyte(self.post_detail_color_func, io_stream) write_ubyte(self.post_detail_alpha_func, io_stream) write_ubyte(self.pad, io_stream) + + def __eq__(self, other): + if not isinstance(other, Shader): + return False + return self.__dict__ == other.__dict__ + + def __ne__(self, other): + return not self.__eq__(other) \ No newline at end of file diff --git a/version_history.txt b/version_history.txt index e31c64de..273316d0 100644 --- a/version_history.txt +++ b/version_history.txt @@ -1,4 +1,9 @@ v0.4.6 +- support alpha values of textures +- support for custom shaders via xml templates +- support prelit materials and multiple material passes +- support for per face materials +- support for vertex colors - apply modifiers to meshes on export - handle export of 'multi-user' meshes From aa47ae3912ac775c9ec669f1c22027275a3208e5 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Sat, 11 Apr 2020 20:39:35 +0200 Subject: [PATCH 41/62] fixed some tests --- .../structs/mesh_structs/shader_material.py | 8 +- .../common/utils/node_group_creator.py | 25 +- .../node_group_templates/DefaultW3D.xml | 10 +- .../node_group_templates/MuzzleFlash.xml | 2 +- .../node_group_templates/NormalMapped.xml | 2 +- .../node_group_templates/ObjectsNOD.xml | 2 +- .../w3d/structs/mesh_structs/shader.py | 5 - .../mesh_structs/test_shader_material.py | 58 ++++- .../helpers/mesh_structs/shader_material.py | 244 +++++++++++------- 9 files changed, 225 insertions(+), 131 deletions(-) diff --git a/io_mesh_w3d/common/structs/mesh_structs/shader_material.py b/io_mesh_w3d/common/structs/mesh_structs/shader_material.py index 97b70ebf..f211e25b 100644 --- a/io_mesh_w3d/common/structs/mesh_structs/shader_material.py +++ b/io_mesh_w3d/common/structs/mesh_structs/shader_material.py @@ -40,7 +40,7 @@ def write(self, io_stream): VEC3_PROPERTY = 4 VEC4_PROPERTY = 5 LONG_PROPERTY = 6 -BYTE_PROPERTY = 7 +BOOL_PROPERTY = 7 class ShaderMaterialProperty: @@ -78,8 +78,8 @@ def read(context, io_stream): result.value = read_vector4(io_stream) elif result.type == LONG_PROPERTY: result.value = read_long(io_stream) - elif result.type == BYTE_PROPERTY: - result.value = read_ubyte(io_stream) + elif result.type == BOOL_PROPERTY: + result.value = bool(read_ubyte(io_stream)) else: context.warning('unknown property type in shader material: ' + str(result.type)) return result @@ -155,7 +155,7 @@ def parse(xml_constant): constant.type = LONG_PROPERTY constant.value = int(values[0]) elif type_name == 'Bool': - constant.type = BYTE_PROPERTY + constant.type = BOOL_PROPERTY constant.value = values[0] in ['True', 'true'] else: constant.type = STRING_PROPERTY diff --git a/io_mesh_w3d/common/utils/node_group_creator.py b/io_mesh_w3d/common/utils/node_group_creator.py index 139175af..fea0aeb7 100644 --- a/io_mesh_w3d/common/utils/node_group_creator.py +++ b/io_mesh_w3d/common/utils/node_group_creator.py @@ -64,25 +64,26 @@ def process_presets(self, socket, xml_node, name=None): self.process_max_value(socket, xml_node.get('max')) + def map_custom_type_to_blender_type(self, type): + if type in ['NodeSocketTexture', 'NodeSocketVector4']: + return 'NodeSocketColor' + if type == 'NodeSocketTextureAlpha': + return 'NodeSocketFloat' + if type == 'NodeSocketVector2': + return 'NodeSocketVector' + if type == 'NodeSocketByte': + return 'NodeSocketInt' + return type + + def create_input_node(self, node_tree, xml_node, node): for child_node in xml_node: if child_node.tag != 'input': continue type = child_node.get('type') + type = self.map_custom_type_to_blender_type(type) name = child_node.get('name') - # those special types are needed for export functionality only - if type == 'NodeSocketTexture': - type = 'NodeSocketColor' - elif type == 'NodeSocketTextureAlpha': - type = 'NodeSocketFloat' - elif type == 'NodeSocketVector2': - type = 'NodeSocketVector' - elif type == 'NodeSocketVector4': - type = 'NodeSocketColor' - elif type == 'NodeSocketByte': - type = 'NodeSocketInt' - socket = node_tree.inputs.new(type, name) self.process_presets(socket, child_node, name) diff --git a/io_mesh_w3d/node_group_templates/DefaultW3D.xml b/io_mesh_w3d/node_group_templates/DefaultW3D.xml index 4fec0937..b464e713 100644 --- a/io_mesh_w3d/node_group_templates/DefaultW3D.xml +++ b/io_mesh_w3d/node_group_templates/DefaultW3D.xml @@ -23,12 +23,12 @@ - - + + - - - + + + diff --git a/io_mesh_w3d/node_group_templates/MuzzleFlash.xml b/io_mesh_w3d/node_group_templates/MuzzleFlash.xml index a9d04fdb..64cb0065 100644 --- a/io_mesh_w3d/node_group_templates/MuzzleFlash.xml +++ b/io_mesh_w3d/node_group_templates/MuzzleFlash.xml @@ -2,9 +2,9 @@ - + diff --git a/io_mesh_w3d/node_group_templates/NormalMapped.xml b/io_mesh_w3d/node_group_templates/NormalMapped.xml index f673d15b..4c55166d 100644 --- a/io_mesh_w3d/node_group_templates/NormalMapped.xml +++ b/io_mesh_w3d/node_group_templates/NormalMapped.xml @@ -6,7 +6,7 @@ - + LON diff --git a/io_mesh_w3d/node_group_templates/ObjectsNOD.xml b/io_mesh_w3d/node_group_templates/ObjectsNOD.xml index 74c261bb..3fa940c6 100644 --- a/io_mesh_w3d/node_group_templates/ObjectsNOD.xml +++ b/io_mesh_w3d/node_group_templates/ObjectsNOD.xml @@ -6,7 +6,7 @@ - + diff --git a/io_mesh_w3d/w3d/structs/mesh_structs/shader.py b/io_mesh_w3d/w3d/structs/mesh_structs/shader.py index 0001e993..9412d68c 100644 --- a/io_mesh_w3d/w3d/structs/mesh_structs/shader.py +++ b/io_mesh_w3d/w3d/structs/mesh_structs/shader.py @@ -69,10 +69,5 @@ def write(self, io_stream): write_ubyte(self.post_detail_alpha_func, io_stream) write_ubyte(self.pad, io_stream) - def __eq__(self, other): - if not isinstance(other, Shader): - return False - return self.__dict__ == other.__dict__ - def __ne__(self, other): return not self.__eq__(other) \ No newline at end of file diff --git a/tests/common/cases/structs/mesh_structs/test_shader_material.py b/tests/common/cases/structs/mesh_structs/test_shader_material.py index 8938f7f2..1cb982ab 100644 --- a/tests/common/cases/structs/mesh_structs/test_shader_material.py +++ b/tests/common/cases/structs/mesh_structs/test_shader_material.py @@ -22,8 +22,7 @@ def test_read_invalid_property(self): size = 8 + len(name) + 1 + 1 type = 0 - write_chunk_head( - W3D_CHUNK_SHADER_MATERIAL_PROPERTY, io_stream, size) + write_chunk_head(W3D_CHUNK_SHADER_MATERIAL_PROPERTY, io_stream, size) write_long(type, io_stream) write_long(len(name) + 1, io_stream) write_string(name, io_stream) @@ -35,7 +34,8 @@ def test_read_invalid_property(self): self.assertEqual(W3D_CHUNK_SHADER_MATERIAL_PROPERTY, chunkType) self.assertEqual(size, chunkSize) - ShaderMaterialProperty.read(self, io_stream) + self.warning = lambda text: self.assertEqual('unknown property type in shader material: 0', text) + actual = ShaderMaterialProperty.read(self, io_stream) def test_write_invalid_property(self): io_stream = io.BytesIO() @@ -116,21 +116,63 @@ def test_chunk_sizes(self): def test_write_read_xml(self): self.write_read_xml_test( - get_shader_material(w3x=True), + get_shader_material(), 'FXShader', ShaderMaterial.parse, compare_shader_materials) - def test_write_read_rgb_colors_xml(self): + def test_write_read_xml(self): + self.write_read_xml_test( + get_shader_material('BasicW3D.fx'), + 'FXShader', + ShaderMaterial.parse, + compare_shader_materials) + + def test_write_read_xml(self): + self.write_read_xml_test( + get_shader_material('DefaultW3D.fx'), + 'FXShader', + ShaderMaterial.parse, + compare_shader_materials) + + def test_write_read_xml(self): + self.write_read_xml_test( + get_shader_material('Infantry.fx'), + 'FXShader', + ShaderMaterial.parse, + compare_shader_materials) + + def test_write_read_xml(self): + self.write_read_xml_test( + get_shader_material('MuzzleFlash.fx'), + 'FXShader', + ShaderMaterial.parse, + compare_shader_materials) + + def test_write_read_xml(self): + self.write_read_xml_test( + get_shader_material('ObjectsAlien.fx'), + 'FXShader', + ShaderMaterial.parse, + compare_shader_materials) + + def test_write_read_xml(self): + self.write_read_xml_test( + get_shader_material('ObjectsGDI.fx'), + 'FXShader', + ShaderMaterial.parse, + compare_shader_materials) + + def test_write_read_xml(self): self.write_read_xml_test( - get_shader_material(two_tex=True, rgb_colors=True), + get_shader_material('ObjectsNOD.fx'), 'FXShader', ShaderMaterial.parse, compare_shader_materials) - def test_write_read_xml_two_texture(self): + def test_write_read_rgb_color_xml(self): self.write_read_xml_test( - get_shader_material(two_tex=True), + get_shader_material(rgb_color=True), 'FXShader', ShaderMaterial.parse, compare_shader_materials) diff --git a/tests/common/helpers/mesh_structs/shader_material.py b/tests/common/helpers/mesh_structs/shader_material.py index fe9f5a1b..bd639493 100644 --- a/tests/common/helpers/mesh_structs/shader_material.py +++ b/tests/common/helpers/mesh_structs/shader_material.py @@ -5,10 +5,10 @@ from tests.mathutils import * -def get_shader_material_header(): +def get_shader_material_header(name='NormalMapped.fx'): return ShaderMaterialHeader( version=1, - type_name='NormalMapped.fx', + type_name=name, technique=0) @@ -26,19 +26,19 @@ def get_shader_material_property( if value is not None: result.value = value - elif _type == 1: + elif _type == STRING_PROPERTY: result.value = tex_name - elif _type == 2: + elif _type == FLOAT_PROPERTY: result.value = 0.25 - elif _type == 3: + elif _type == VEC2_PROPERTY: result.value = get_vec2(x=1.0, y=0.5) - elif _type == 4: + elif _type == VEC3_PROPERTY: result.value = get_vec(x=1.0, y=0.2, z=0.33) - elif _type == 5: + elif _type == VEC4_PROPERTY: result.value = get_vec4(x=0.33, y=0.3, z=0.1, w=1.0) - elif _type == 6: + elif _type == LONG_PROPERTY: result.value = 3 - elif _type == 7: + elif _type == BOOL_PROPERTY: result.value = True return result @@ -48,101 +48,157 @@ def compare_shader_material_properties(self, expected, actual): self.assertEqual(expected.type, actual.type, 'Incorrect type: ' + str(actual.type) + ' for property: ' + actual.name) - if expected.type == 1: + if expected.type == STRING_PROPERTY: self.assertEqual(expected.value.split('.')[0], actual.value.split('.')[0]) - elif expected.type == 2: + elif expected.type == FLOAT_PROPERTY: self.assertAlmostEqual(expected.value, actual.value, 5) - elif expected.type == 3: + elif expected.type == VEC2_PROPERTY: compare_vectors2(self, expected.value, actual.value) - elif expected.type == 4: + elif expected.type == VEC3_PROPERTY: compare_vectors(self, expected.value, actual.value) - elif expected.type == 5: + elif expected.type == VEC4_PROPERTY: compare_vectors4(self, expected.value, actual.value) else: self.assertEqual(expected.value, actual.value) -def get_shader_material_properties(w3x=False, two_tex=False, rgb_colors=False): - props = [ - get_shader_material_property(3, 'BumpUVScale'), - get_shader_material_property(6, 'BlendMode'), - get_shader_material_property(7, 'AlphaTestEnable', value=False), - get_shader_material_property(7, 'CullingEnable'), - get_shader_material_property(2, 'Opacity'), - get_shader_material_property(6, 'EdgeFadeOut'), - get_shader_material_property(7, 'DepthWriteEnable'), - get_shader_material_property(5, 'Sampler_ClampU_ClampV_NoMip_0'), - get_shader_material_property(5, 'Sampler_ClampU_ClampV_NoMip_1'), - get_shader_material_property(1, 'EnvironmentTexture', 'texture_env.tga'), - get_shader_material_property(2, 'EnvMult'), - get_shader_material_property(1, 'RecolorTexture'), - get_shader_material_property(2, 'RecolorMultiplier'), - get_shader_material_property(7, 'UseRecolorColors'), - get_shader_material_property(7, 'HouseColorPulse'), - get_shader_material_property(1, 'ScrollingMaskTexture', 'texture_scroll.dds'), - get_shader_material_property(2, 'TexCoordTransformAngle_0'), - get_shader_material_property(2, 'TexCoordTransformU_0'), - get_shader_material_property(2, 'TexCoordTransformV_0'), - get_shader_material_property(2, 'TexCoordTransformU_1'), - get_shader_material_property(2, 'TexCoordTransformV_1'), - get_shader_material_property(2, 'TexCoordTransformU_2'), - get_shader_material_property(2, 'TexCoordTransformV_2'), - get_shader_material_property(5, 'TextureAnimation_FPS_NumPerRow_LastFrame_FrameOffset_0'), - get_shader_material_property(1, 'IonHullTexture'), - get_shader_material_property(7, 'MultiTextureEnable')] - - if w3x: - props.append(get_shader_material_property(2, 'Shininess', value=125.0)) - - if rgb_colors: - props.append(get_shader_material_property(4, 'ColorDiffuse', value=get_vec(x=0.2, y=0.33, z=0.9))) - props.append(get_shader_material_property(4, 'ColorSpecular', value=get_vec(x=0.2, y=0.33, z=0.9))) - props.append(get_shader_material_property(4, 'ColorAmbient', value=get_vec(x=0.2, y=0.33, z=0.9))) - props.append(get_shader_material_property(4, 'ColorEmissive', value=get_vec(x=0.2, y=0.33, z=0.9))) - else: - props.append(get_shader_material_property(5, 'ColorDiffuse')) - props.append(get_shader_material_property(5, 'ColorSpecular')) - props.append(get_shader_material_property(5, 'ColorAmbient')) - props.append(get_shader_material_property(5, 'ColorEmissive')) - else: - props.append(get_shader_material_property(2, 'SpecularExponent', value=125.0)) - props.append(get_shader_material_property(5, 'DiffuseColor')) - props.append(get_shader_material_property(5, 'SpecularColor')) - props.append(get_shader_material_property(5, 'AmbientColor')) - props.append(get_shader_material_property(5, 'EmissiveColor')) - - if two_tex: - props.append(get_shader_material_property(6, 'NumTextures', value=2)) - props.append(get_shader_material_property(1, 'Texture_0', 'texture_0.dds')) - props.append(get_shader_material_property(1, 'Texture_1', 'texture_1.dds')) - props.append(get_shader_material_property(6, 'SecondaryTextureBlendMode')) - props.append(get_shader_material_property(6, 'TexCoordMapper_0')) - props.append(get_shader_material_property(6, 'TexCoordMapper_1')) - props.append(get_shader_material_property(5, 'TexCoordTransform_0')) - props.append(get_shader_material_property(5, 'TexCoordTransform_1')) - else: - props.append(get_shader_material_property(1, 'DiffuseTexture')) - props.append(get_shader_material_property(1, 'NormalMap', 'texture_nrm.dds')) - props.append(get_shader_material_property(2, 'BumpScale')) - props.append(get_shader_material_property(1, 'SpecMap', 'texture_spec.dds')) - return props - - -def get_shader_material_properties_minimal(): - return [ - get_shader_material_property(2, 'SpecularExponent'), - get_shader_material_property(3, 'BumpUVScale'), - get_shader_material_property(4, 'SpecularColor'), - get_shader_material_property(5, 'AmbientColor'), - get_shader_material_property(5, 'DiffuseColor'), - get_shader_material_property(6, 'BlendMode'), - get_shader_material_property(7, 'AlphaTestEnable', value=False)] - - -def get_shader_material(w3x=False, two_tex=False, rgb_colors=False): +def get_shader_material_properties(name, rgb_color=False): + if name == 'NormalMapped.fx': + ambient = get_shader_material_property(VEC4_PROPERTY, 'AmbientColor') + if rgb_color: + ambient = get_shader_material_property(VEC3_PROPERTY, 'AmbientColor') + + return [ + get_shader_material_property(VEC4_PROPERTY, 'DiffuseColor'), + get_shader_material_property(STRING_PROPERTY, 'DiffuseTexture'), + get_shader_material_property(BOOL_PROPERTY, 'AlphaTestEnable', value=False), + get_shader_material_property(STRING_PROPERTY, 'NormalMap', 'texture_nrm.dds'), + get_shader_material_property(FLOAT_PROPERTY, 'BumpScale'), + ambient, + get_shader_material_property(VEC4_PROPERTY, 'SpecularColor'), + get_shader_material_property(FLOAT_PROPERTY, 'SpecularExponent')] + + elif name == 'BasicW3D.fx': + return [ + get_shader_material_property(VEC4_PROPERTY, 'ColorDiffuse'), + get_shader_material_property(STRING_PROPERTY, 'Texture_0'), + get_shader_material_property(STRING_PROPERTY, 'Texture_1', 'texture_1.dds'), + get_shader_material_property(BOOL_PROPERTY, 'AlphaTestEnable', value=False), + get_shader_material_property(VEC4_PROPERTY, 'ColorAmbient'), + get_shader_material_property(VEC4_PROPERTY, 'ColorSpecular'), + get_shader_material_property(FLOAT_PROPERTY, 'Shininess'), + get_shader_material_property(VEC4_PROPERTY, 'ColorEmissive'), + get_shader_material_property(BOOL_PROPERTY, 'DepthWriteEnable'), + get_shader_material_property(BOOL_PROPERTY, 'CullingEnable'), + get_shader_material_property(LONG_PROPERTY, 'BlendMode')] + + elif name == 'DefaultW3D.fx': + return [ + get_shader_material_property(VEC4_PROPERTY, 'ColorDiffuse'), + get_shader_material_property(STRING_PROPERTY, 'Texture_0'), + get_shader_material_property(STRING_PROPERTY, 'Texture_1', 'texture_1.dds'), + get_shader_material_property(BOOL_PROPERTY, 'AlphaTestEnable', value=False), + get_shader_material_property(VEC4_PROPERTY, 'ColorAmbient'), + get_shader_material_property(VEC4_PROPERTY, 'ColorSpecular'), + get_shader_material_property(FLOAT_PROPERTY, 'Shininess'), + get_shader_material_property(VEC4_PROPERTY, 'ColorEmissive'), + get_shader_material_property(FLOAT_PROPERTY, 'Opacity'), + get_shader_material_property(LONG_PROPERTY, 'NumTextures'), + get_shader_material_property(BOOL_PROPERTY, 'DepthWriteEnable'), + get_shader_material_property(BOOL_PROPERTY, 'CullingEnable'), + get_shader_material_property(LONG_PROPERTY, 'BlendMode'), + get_shader_material_property(FLOAT_PROPERTY, 'EdgeFadeOut'), + get_shader_material_property(BOOL_PROPERTY, 'UseRecolorColors'), + get_shader_material_property(BOOL_PROPERTY, 'HouseColorPulse'), + get_shader_material_property(LONG_PROPERTY, 'SecondaryTextureBlendMode'), + get_shader_material_property(VEC4_PROPERTY, 'TexCoordMapper_0'), + get_shader_material_property(VEC4_PROPERTY, 'TexCoordTransform_0'), + get_shader_material_property(VEC4_PROPERTY, 'TextureAnimation_FPS_NumPerRow_LastFrame_FrameOffset_0'), + get_shader_material_property(LONG_PROPERTY, 'TexCoordMapper_1'), + get_shader_material_property(VEC4_PROPERTY, 'TexCoordTransform_1'), + get_shader_material_property(VEC4_PROPERTY, 'Sampler_ClampU_ClampV_NoMip_0'), + get_shader_material_property(VEC4_PROPERTY, 'Sampler_ClampU_ClampV_NoMip_1')] + + elif name == 'Infantry.fx': + return [ + get_shader_material_property(VEC4_PROPERTY, 'ColorDiffuse'), + get_shader_material_property(STRING_PROPERTY, 'Texture_0'), + get_shader_material_property(STRING_PROPERTY, 'Texture_1', 'texture_1.dds'), + get_shader_material_property(BOOL_PROPERTY, 'AlphaTestEnable', value=False), + get_shader_material_property(STRING_PROPERTY, 'RecolorTexture', 'texture_rec.dds'), + get_shader_material_property(VEC4_PROPERTY, 'ColorAmbient'), + get_shader_material_property(VEC4_PROPERTY, 'ColorSpecular'), + get_shader_material_property(FLOAT_PROPERTY, 'Shininess'), + get_shader_material_property(VEC4_PROPERTY, 'ColorEmissive'), + get_shader_material_property(BOOL_PROPERTY, 'DepthWriteEnable'), + get_shader_material_property(BOOL_PROPERTY, 'CullingEnable'), + get_shader_material_property(LONG_PROPERTY, 'BlendMode')] + + elif name == 'MuzzleFlash.fx': + return [ + get_shader_material_property(STRING_PROPERTY, 'Texture_0'), + get_shader_material_property(VEC4_PROPERTY, 'ColorEmissive'), + get_shader_material_property(FLOAT_PROPERTY, 'TexCoordTransformAngle_0'), + get_shader_material_property(FLOAT_PROPERTY, 'TexCoordTransformU_0'), + get_shader_material_property(FLOAT_PROPERTY, 'TexCoordTransformV_0'), + get_shader_material_property(FLOAT_PROPERTY, 'TexCoordTransformU_1'), + get_shader_material_property(FLOAT_PROPERTY, 'TexCoordTransformV_1'), + get_shader_material_property(FLOAT_PROPERTY, 'TexCoordTransformU_2'), + get_shader_material_property(FLOAT_PROPERTY, 'TexCoordTransformV_2')] + + elif name == 'ObjectsGDI.fx': + return [ + get_shader_material_property(VEC4_PROPERTY, 'DiffuseColor'), + get_shader_material_property(STRING_PROPERTY, 'DiffuseTexture'), + get_shader_material_property(BOOL_PROPERTY, 'AlphaTestEnable', value=False), + get_shader_material_property(STRING_PROPERTY, 'NormalMap', 'texture_nrm.dds'), + get_shader_material_property(FLOAT_PROPERTY, 'BumpScale'), + get_shader_material_property(VEC4_PROPERTY, 'AmbientColor'), + get_shader_material_property(VEC4_PROPERTY, 'SpecularColor'), + get_shader_material_property(FLOAT_PROPERTY, 'SpecularExponent'), + get_shader_material_property(STRING_PROPERTY, 'SpecMap', 'texture_spec.dds'), + get_shader_material_property(STRING_PROPERTY, 'RecolorTexture', 'texture_rec.dds'), + get_shader_material_property(FLOAT_PROPERTY, 'EnvMult')] + + elif name == 'ObjectsAlien.fx': + return [ + get_shader_material_property(VEC4_PROPERTY, 'DiffuseColor'), + get_shader_material_property(STRING_PROPERTY, 'DiffuseTexture'), + get_shader_material_property(BOOL_PROPERTY, 'AlphaTestEnable', value=False), + get_shader_material_property(STRING_PROPERTY, 'NormalMap', 'texture_nrm.dds'), + get_shader_material_property(FLOAT_PROPERTY, 'BumpScale'), + get_shader_material_property(VEC4_PROPERTY, 'AmbientColor'), + get_shader_material_property(VEC4_PROPERTY, 'SpecularColor'), + get_shader_material_property(FLOAT_PROPERTY, 'SpecularExponent'), + get_shader_material_property(STRING_PROPERTY, 'SpecMap', 'texture_spec.dds'), + get_shader_material_property(STRING_PROPERTY, 'RecolorTexture', 'texture_rec.dds'), + get_shader_material_property(FLOAT_PROPERTY, 'EnvMult'), + get_shader_material_property(STRING_PROPERTY, 'EnvironmentTexture', 'texture_env.dds')] + + elif name == 'ObjectsNOD.fx': + return [ + get_shader_material_property(VEC4_PROPERTY, 'DiffuseColor'), + get_shader_material_property(STRING_PROPERTY, 'DiffuseTexture'), + get_shader_material_property(BOOL_PROPERTY, 'AlphaTestEnable', value=False), + get_shader_material_property(STRING_PROPERTY, 'NormalMap', 'texture_nrm.dds'), + get_shader_material_property(FLOAT_PROPERTY, 'BumpScale'), + get_shader_material_property(VEC4_PROPERTY, 'AmbientColor'), + get_shader_material_property(VEC4_PROPERTY, 'SpecularColor'), + get_shader_material_property(FLOAT_PROPERTY, 'SpecularExponent'), + get_shader_material_property(STRING_PROPERTY, 'SpecMap', 'texture_spec.dds'), + get_shader_material_property(STRING_PROPERTY, 'ScrollingMaskTexture', 'texture_scroll.dds'), + get_shader_material_property(VEC4_PROPERTY, 'TexCoordTransform_0'), + get_shader_material_property(FLOAT_PROPERTY, 'RecolorMultiplier'), + get_shader_material_property(FLOAT_PROPERTY, 'EnvMult')] + + print('NO SHADER PROPERTY SET DEFINED FOR : ' + name) + return [] + + +def get_shader_material(name='NormalMapped.fx', rgb_color=False): return ShaderMaterial( - header=get_shader_material_header(), - properties=get_shader_material_properties(w3x, two_tex, rgb_colors)) + header=get_shader_material_header(name), + properties=get_shader_material_properties(name, rgb_color)) def get_shader_material_minimal(): From f5ec013a501c0729a13b6daa3f3aa9bb77c8f7a2 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Sun, 12 Apr 2020 12:44:39 +0200 Subject: [PATCH 42/62] some small changes --- io_mesh_w3d/common/node_groups/helpers.py | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 io_mesh_w3d/common/node_groups/helpers.py diff --git a/io_mesh_w3d/common/node_groups/helpers.py b/io_mesh_w3d/common/node_groups/helpers.py deleted file mode 100644 index e7b94049..00000000 --- a/io_mesh_w3d/common/node_groups/helpers.py +++ /dev/null @@ -1,8 +0,0 @@ -# -# Written by Stephan Vedder and Michael Schnabel - -def addInputInt(group, name, default=0, min=0, max=255): - group.inputs.new('NodeSocketInt', name) - group.inputs[name].default_value = default - group.inputs[name].min_value = min - group.inputs[name].max_value = max From 7f165bc99be405141b00f3d7e4b061e0c6bbeb5f Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Sun, 12 Apr 2020 12:46:43 +0200 Subject: [PATCH 43/62] some small changes --- io_mesh_w3d/__init__.py | 7 +-- .../common/node_groups/vertex_material.py | 53 ++++++++----------- io_mesh_w3d/common/utils/material_import.py | 3 -- tests/w3x/cases/test_roundtrip.py | 1 + 4 files changed, 26 insertions(+), 38 deletions(-) diff --git a/io_mesh_w3d/__init__.py b/io_mesh_w3d/__init__.py index 4b236dee..cf4f57f8 100644 --- a/io_mesh_w3d/__init__.py +++ b/io_mesh_w3d/__init__.py @@ -7,6 +7,7 @@ from io_mesh_w3d.export_utils import save from io_mesh_w3d.custom_properties import * + bl_info = { 'name': 'Import/Export Westwood W3D Format (.w3d/.w3x)', 'author': 'OpenSage Developers', @@ -299,12 +300,8 @@ def register_node_groups(): continue NodeGroupCreator().create(directory, file) - from io_mesh_w3d.common.node_groups.vertex_material import VertexMaterialGroup, PrelitUnlitGroup, PrelitVertexGroup, PrelitLightmapMultiPassGroup, PrelitLightmapMultiTextureGroup + from io_mesh_w3d.common.node_groups.vertex_material import VertexMaterialGroup VertexMaterialGroup.register(VertexMaterialGroup.name) - PrelitUnlitGroup.register(PrelitUnlitGroup.name) - PrelitVertexGroup.register(PrelitVertexGroup.name) - PrelitLightmapMultiPassGroup.register(PrelitLightmapMultiPassGroup.name) - PrelitLightmapMultiTextureGroup.register(PrelitLightmapMultiTextureGroup.name) def register(): for class_ in CLASSES: diff --git a/io_mesh_w3d/common/node_groups/vertex_material.py b/io_mesh_w3d/common/node_groups/vertex_material.py index df099b9d..3a05c772 100644 --- a/io_mesh_w3d/common/node_groups/vertex_material.py +++ b/io_mesh_w3d/common/node_groups/vertex_material.py @@ -2,7 +2,6 @@ # Written by Stephan Vedder and Michael Schnabel import bpy -from io_mesh_w3d.common.node_groups.helpers import * class VertexMaterialGroup(): @@ -13,7 +12,7 @@ def create(node_tree, name, vm_info, shader): instance = node_tree.nodes.new(type='ShaderNodeGroup') instance.location = (0, 300) instance.width = 300 - # TODO: depending on prelit type + instance.node_tree = bpy.data.node_groups['VertexMaterial'] instance.label = name @@ -42,6 +41,13 @@ def create(node_tree, name, vm_info, shader): return instance + @staticmethod + def addInputInt(group, name, default=0, min=0, max=255): + group.inputs.new('NodeSocketInt', name) + group.inputs[name].default_value = default + group.inputs[name].min_value = min + group.inputs[name].max_value = max + @staticmethod def register(name): group = bpy.data.node_groups.new(name, 'ShaderNodeTree') @@ -57,7 +63,7 @@ def register(name): group.inputs.new('NodeSocketColor', 'DiffuseTexture') group.inputs.new('NodeSocketFloat', 'DiffuseTextureAlpha') group.inputs['DiffuseTextureAlpha'].default_value = 0.0 - addInputInt(group, 'DestBlend', max=1) + VertexMaterialGroup.addInputInt(group, 'DestBlend', max=1) group.inputs.new('NodeSocketColor', 'Ambient') group.inputs['Ambient'].default_value = (0.8, 0.8, 0.8, 1.0) group.inputs.new('NodeSocketColor', 'Specular') @@ -68,20 +74,20 @@ def register(name): group.inputs.new('NodeSocketFloat', 'Opacity') group.inputs.new('NodeSocketFloat', 'Translucency') - addInputInt(group, 'DepthCompare') - addInputInt(group, 'DepthMask') - addInputInt(group, 'ColorMask') - addInputInt(group, 'FogFunc') - addInputInt(group, 'PriGradient') - addInputInt(group, 'SecGradient') - addInputInt(group, 'SrcBlend') - addInputInt(group, 'Texturing') - addInputInt(group, 'DetailColorFunc') - addInputInt(group, 'DetailAlphaFunc') - addInputInt(group, 'Preset') - addInputInt(group, 'AlphaTest') - addInputInt(group, 'PostDetailColorFunc') - addInputInt(group, 'PostDetailAlphaFunc') + VertexMaterialGroup.addInputInt(group, 'DepthCompare') + VertexMaterialGroup.addInputInt(group, 'DepthMask') + VertexMaterialGroup.addInputInt(group, 'ColorMask') + VertexMaterialGroup.addInputInt(group, 'FogFunc') + VertexMaterialGroup.addInputInt(group, 'PriGradient') + VertexMaterialGroup.addInputInt(group, 'SecGradient') + VertexMaterialGroup.addInputInt(group, 'SrcBlend') + VertexMaterialGroup.addInputInt(group, 'Texturing') + VertexMaterialGroup.addInputInt(group, 'DetailColorFunc') + VertexMaterialGroup.addInputInt(group, 'DetailAlphaFunc') + VertexMaterialGroup.addInputInt(group, 'Preset') + VertexMaterialGroup.addInputInt(group, 'AlphaTest') + VertexMaterialGroup.addInputInt(group, 'PostDetailColorFunc') + VertexMaterialGroup.addInputInt(group, 'PostDetailAlphaFunc') # create group outputs group_outputs = group.nodes.new('NodeGroupOutput') @@ -107,16 +113,3 @@ def register(name): links.new(group_inputs.outputs['Emissive'], shader.inputs['Emissive Color']) links.new(alpha_pipeline.outputs['Alpha'], shader.inputs['Transparency']) links.new(shader.outputs['BSDF'], group_outputs.inputs['BSDF']) - - -class PrelitUnlitGroup(VertexMaterialGroup): - name = 'PrelitUnlit' - -class PrelitVertexGroup(VertexMaterialGroup): - name = 'PrelitVertex' - -class PrelitLightmapMultiPassGroup(VertexMaterialGroup): - name = 'PrelitLightmapMultiPass' - -class PrelitLightmapMultiTextureGroup(VertexMaterialGroup): - name = 'PrelitLightmapMultiTextue' diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index 63d6d08a..3ade2455 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -6,7 +6,6 @@ from bpy_extras import node_shader_utils from io_mesh_w3d.common.node_groups.vertex_material import * -from io_mesh_w3d.common.node_groups.helpers import * from io_mesh_w3d.common.utils.helpers import * from io_mesh_w3d.w3d.structs.mesh_structs.vertex_material import * from io_mesh_w3d.common.structs.mesh_structs.shader_material import * @@ -132,8 +131,6 @@ def create_shader_material(context, mesh, b_mesh, triangles, shader_mat, tx_coor material.show_transparent_back = False node_tree = material.node_tree - links = node_tree.links - node_tree.nodes.remove(node_tree.nodes.get('Principled BSDF')) instance = node_tree.nodes.new(type='ShaderNodeGroup') diff --git a/tests/w3x/cases/test_roundtrip.py b/tests/w3x/cases/test_roundtrip.py index 20524cc4..46a6f0fa 100644 --- a/tests/w3x/cases/test_roundtrip.py +++ b/tests/w3x/cases/test_roundtrip.py @@ -108,6 +108,7 @@ def test_roundtrip_HAM(self): self.assertTrue('TRUNK' in bpy.data.objects) def test_roundtrip_texture_name_with_dots(self): + self.info = print hierarchy_name = 'testname_skl' hierarchy = get_hierarchy(hierarchy_name) mesh = get_mesh(name='sword', skin=True) From 794b448343bb1c75570dc489c034093b40ef6f51 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Mon, 13 Apr 2020 20:32:48 +0200 Subject: [PATCH 44/62] create custom node socket types --- io_mesh_w3d/__init__.py | 81 +++++++---- .../common/shading/node_socket_enum.py | 45 +++++++ .../common/shading/node_socket_texture.py | 16 +++ .../shading/node_socket_texture_alpha.py | 25 ++++ .../common/shading/node_socket_vec2.py | 27 ++++ .../common/shading/node_socket_vec4.py | 27 ++++ .../vertex_material_group.py} | 50 +++++-- io_mesh_w3d/common/utils/box_import.py | 2 +- io_mesh_w3d/common/utils/material_export.py | 22 +-- io_mesh_w3d/common/utils/material_import.py | 24 +--- io_mesh_w3d/common/utils/mesh_import.py | 4 +- .../common/utils/node_group_creator.py | 13 -- io_mesh_w3d/custom_properties.py | 126 ++++++++---------- 13 files changed, 308 insertions(+), 154 deletions(-) create mode 100644 io_mesh_w3d/common/shading/node_socket_enum.py create mode 100644 io_mesh_w3d/common/shading/node_socket_texture.py create mode 100644 io_mesh_w3d/common/shading/node_socket_texture_alpha.py create mode 100644 io_mesh_w3d/common/shading/node_socket_vec2.py create mode 100644 io_mesh_w3d/common/shading/node_socket_vec4.py rename io_mesh_w3d/common/{node_groups/vertex_material.py => shading/vertex_material_group.py} (69%) diff --git a/io_mesh_w3d/__init__.py b/io_mesh_w3d/__init__.py index cf4f57f8..ba4aed14 100644 --- a/io_mesh_w3d/__init__.py +++ b/io_mesh_w3d/__init__.py @@ -225,12 +225,13 @@ def menu_func_export(self, _context): def menu_func_import(self, _context): self.layout.operator(ImportW3D.bl_idname, text='Westwood W3D (.w3d/.w3x)') +from bpy.types import Panel -class OBJECT_PROPERTIES_PANEL_PT_w3d(Panel): +class MESH_PROPERTIES_PANEL_PT_w3d(Panel): bl_label = 'W3D Properties' bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' - bl_context = 'object' + bl_context = 'mesh' def draw(self, context): layout = self.layout @@ -256,39 +257,63 @@ def draw(self, context): col.prop(context.active_bone, 'visibility') -class MATERIAL_PROPERTIES_PANEL_PT_w3d(Panel): +class MESH_POLYGON_PROPERTIES_PANEL_PT_w3d(Panel): bl_label = 'W3D Properties' bl_space_type = 'PROPERTIES' - bl_region_type = 'WINDOW' - bl_context = 'material' + bl_region_type = 'PANEL' + bl_context = 'mesh polygon' def draw(self, context): layout = self.layout - mat = context.object.active_material - - for node in mat.node_tree.nodes: - - if not hasattr(node, 'node_tree'): - continue - print(node.node_tree.name) - if node.node_tree.name in ['VertexMaterial', 'PrelitUnlit', 'PrelitVertex', 'PrelitLightmapMultiPass', 'PrelitLightmapMultiTextue']: - col = layout.column() - col.prop(mat, 'surface_type') - col = layout.column() - col.prop(mat, 'attributes') - col = layout.column() - col.prop(mat, 'vm_args_0') - col = layout.column() - col.prop(mat, 'vm_args_1') + if context.active_polygon is not None: + col = layout.column() + col.prop(context.active_bone, 'visibility') + + +import nodeitems_utils +from nodeitems_utils import NodeCategory, NodeItem + +# all categories in a list +node_categories = [ + # identifier, label, items list + NodeCategory('SOMENODES', 'Some Nodes', items=[ + # our basic node + NodeItem('DecisionNode'), + ]), + NodeCategory('OTHERNODES', "Other Nodes", items=[ + # the node item can have additional settings, + # which are applied to new nodes + # NB: settings values are stored as string expressions, + # for this reason they should be converted to strings using repr() + NodeItem("CustomNodeType", label="Node A", settings={ + "my_string_prop": repr("Lorem ipsum dolor sit amet"), + "my_float_prop": repr(1.0), + }), + NodeItem("CustomNodeType", label="Node B", settings={ + "my_string_prop": repr("consectetur adipisicing elit"), + "my_float_prop": repr(2.0), + }), + ]), +] + + +from io_mesh_w3d.common.shading.node_socket_texture import NodeSocketTexture +from io_mesh_w3d.common.shading.node_socket_texture_alpha import NodeSocketTextureAlpha +from io_mesh_w3d.common.shading.node_socket_vec2 import NodeSocketVector2 +from io_mesh_w3d.common.shading.node_socket_vec4 import NodeSocketVector4 +from io_mesh_w3d.common.shading.node_socket_enum import NodeSocketMaterialAttributes CLASSES = ( + NodeSocketTexture, + NodeSocketTextureAlpha, + NodeSocketVector2, + NodeSocketVector4, + NodeSocketMaterialAttributes, ExportW3D, ImportW3D, - OBJECT_PROPERTIES_PANEL_PT_w3d, - BONE_PROPERTIES_PANEL_PT_w3d, - MATERIAL_PROPERTIES_PANEL_PT_w3d -) + MESH_PROPERTIES_PANEL_PT_w3d, + BONE_PROPERTIES_PANEL_PT_w3d) def register_node_groups(): from io_mesh_w3d.common.utils.node_group_creator import NodeGroupCreator @@ -300,13 +325,15 @@ def register_node_groups(): continue NodeGroupCreator().create(directory, file) - from io_mesh_w3d.common.node_groups.vertex_material import VertexMaterialGroup + from io_mesh_w3d.common.shading.vertex_material_group import VertexMaterialGroup VertexMaterialGroup.register(VertexMaterialGroup.name) def register(): for class_ in CLASSES: bpy.utils.register_class(class_) + nodeitems_utils.register_node_categories('CUSTOM_NODES', node_categories) + bpy.types.TOPBAR_MT_file_import.append(menu_func_import) bpy.types.TOPBAR_MT_file_export.append(menu_func_export) @@ -319,6 +346,8 @@ def register(): def unregister(): + nodeitems_utils.unregister_node_categories('CUSTOM_NODES') + for class_ in reversed(CLASSES): bpy.utils.unregister_class(class_) bpy.types.TOPBAR_MT_file_import.remove(menu_func_import) diff --git a/io_mesh_w3d/common/shading/node_socket_enum.py b/io_mesh_w3d/common/shading/node_socket_enum.py new file mode 100644 index 00000000..41a30961 --- /dev/null +++ b/io_mesh_w3d/common/shading/node_socket_enum.py @@ -0,0 +1,45 @@ +# +# Written by Stephan Vedder and Michael Schnabel + +import bpy +from bpy.types import NodeSocket + + +class NodeSocketEnum(NodeSocket): + bl_idname = 'NodeSocketEnum' + bl_label = 'Enum Node Socket' + + my_enum_prop: bpy.props.EnumProperty( + name="Direction", + description="Just an example", + items=[ + ('DOWN', "Down", "Where your feet are"), + ('UP', "Up", "Where your head should be"), + ('LEFT', "Left", "Not right"), + ('RIGHT', "Right", "Not left")], + default='UP') + + def draw(self, context, layout, node, text): + if self.is_output or self.is_linked: + layout.label(text=text) + else: + layout.prop(self, "my_enum_prop", text=text) + + def draw_color(self, context, node): + return (1.0, 0.4, 0.216, 0.5) + +class NodeSocketMaterialAttributes(NodeSocketEnum): + bl_idname = 'NodeSocketMaterialAttributes' + bl_label = "Material Attributes Enum Flag Node Socket" + + my_enum_prop: bpy.props.EnumProperty( + name='Attributes', + description='Attributes that define the behaviour of this material', + items=[ + ('DEFAULT', 'Default', 'desc: todo', 0), + ('USE_DEPTH_CUE', 'UseDepthCue', 'desc: todo', 1), + ('ARGB_EMISSIVE_ONLY', 'ArgbEmissiveOnly', 'desc: todo', 2), + ('COPY_SPECULAR_TO_DIFFUSE', 'CopySpecularToDiffuse', 'desc: todo', 4), + ('DEPTH_CUE_TO_ALPHA', 'DepthCueToAlpha', 'desc: todo', 8)], + default=set(), + options={'ENUM_FLAG'}) \ No newline at end of file diff --git a/io_mesh_w3d/common/shading/node_socket_texture.py b/io_mesh_w3d/common/shading/node_socket_texture.py new file mode 100644 index 00000000..6e54c393 --- /dev/null +++ b/io_mesh_w3d/common/shading/node_socket_texture.py @@ -0,0 +1,16 @@ +# +# Written by Stephan Vedder and Michael Schnabel + +import bpy +from bpy.types import NodeSocketColor + + +class NodeSocketTexture(NodeSocketColor): + bl_idname = 'NodeSocketTexture' + bl_label = 'Texture Node Socket' + + def draw(self, context, layout, node, text): + layout.label(text=text) + + def draw_color(self, context, node): + return (1.0, 0.4, 0.216, 0.5) diff --git a/io_mesh_w3d/common/shading/node_socket_texture_alpha.py b/io_mesh_w3d/common/shading/node_socket_texture_alpha.py new file mode 100644 index 00000000..465258c2 --- /dev/null +++ b/io_mesh_w3d/common/shading/node_socket_texture_alpha.py @@ -0,0 +1,25 @@ +# +# Written by Stephan Vedder and Michael Schnabel + +import bpy +from bpy.types import NodeSocket + + +class NodeSocketTextureAlpha(NodeSocket): + bl_idname = 'NodeSocketTextureAlpha' + bl_label = 'Texture Alpha Node Socket' + + float_prop: bpy.props.FloatProperty( + name='Texture Alpha', + default=1.0, + min=0.0, max=1.0, + description='Texture alpha property') + + def draw(self, context, layout, node, text): + if self.is_output or self.is_linked: + layout.label(text=text) + else: + layout.prop(self, "float_prop", text=text) + + def draw_color(self, context, node): + return (1.0, 0.4, 0.216, 0.5) diff --git a/io_mesh_w3d/common/shading/node_socket_vec2.py b/io_mesh_w3d/common/shading/node_socket_vec2.py new file mode 100644 index 00000000..f67dbbd3 --- /dev/null +++ b/io_mesh_w3d/common/shading/node_socket_vec2.py @@ -0,0 +1,27 @@ +# +# Written by Stephan Vedder and Michael Schnabel + +import bpy +from bpy.types import NodeSocket + + +class NodeSocketVector2(NodeSocket): + bl_idname = 'NodeSocketVector2' + bl_label = 'Vector2 Node Socket' + + vec2_prop: bpy.props.FloatVectorProperty( + name='Vector2', + subtype='TRANSLATION', + size=2, + default=(0.0, 0.0), + min=0.0, max=1.0, + description='Vector 2') + + def draw(self, context, layout, node, text): + if self.is_output or self.is_linked: + layout.label(text=text) + else: + layout.prop(self, "vec2_prop", text=text) + + def draw_color(self, context, node): + return (1.0, 0.4, 0.216, 0.5) diff --git a/io_mesh_w3d/common/shading/node_socket_vec4.py b/io_mesh_w3d/common/shading/node_socket_vec4.py new file mode 100644 index 00000000..4ccaa2be --- /dev/null +++ b/io_mesh_w3d/common/shading/node_socket_vec4.py @@ -0,0 +1,27 @@ +# +# Written by Stephan Vedder and Michael Schnabel + +import bpy +from bpy.types import NodeSocket + + +class NodeSocketVector4(NodeSocket): + bl_idname = 'NodeSocketVector4' + bl_label = 'Vector4 Node Socket' + + vec2_prop: bpy.props.FloatVectorProperty( + name='Vector4', + subtype='TRANSLATION', + size=4, + default=(0.0, 0.0, 0.0, 0.0), + min=0.0, max=1.0, + description='Vector 4') + + def draw(self, context, layout, node, text): + if self.is_output or self.is_linked: + layout.label(text=text) + else: + layout.prop(self, "vec2_prop", text=text) + + def draw_color(self, context, node): + return (1.0, 0.4, 0.216, 0.5) diff --git a/io_mesh_w3d/common/node_groups/vertex_material.py b/io_mesh_w3d/common/shading/vertex_material_group.py similarity index 69% rename from io_mesh_w3d/common/node_groups/vertex_material.py rename to io_mesh_w3d/common/shading/vertex_material_group.py index 3a05c772..ac3ee3aa 100644 --- a/io_mesh_w3d/common/node_groups/vertex_material.py +++ b/io_mesh_w3d/common/shading/vertex_material_group.py @@ -2,27 +2,50 @@ # Written by Stephan Vedder and Michael Schnabel import bpy +from io_mesh_w3d.w3d.structs.mesh_structs.vertex_material import * class VertexMaterialGroup(): name = 'VertexMaterial' @staticmethod - def create(node_tree, name, vm_info, shader): + def create(node_tree, vert_mat, shader): instance = node_tree.nodes.new(type='ShaderNodeGroup') instance.location = (0, 300) instance.width = 300 instance.node_tree = bpy.data.node_groups['VertexMaterial'] - instance.label = name - - instance.inputs['Diffuse'].default_value = vm_info.diffuse.to_vector_rgba() - instance.inputs['Ambient'].default_value = vm_info.ambient.to_vector_rgba() - instance.inputs['Specular'].default_value = vm_info.specular.to_vector_rgba() - instance.inputs['Emissive'].default_value = vm_info.emissive.to_vector_rgba() - instance.inputs['Shininess'].default_value = vm_info.shininess - instance.inputs['Opacity'].default_value = vm_info.shininess - instance.inputs['Translucency'].default_value = vm_info.shininess + instance.label = vert_mat.vm_name + + attributes = {'DEFAULT'} + attributes = vert_mat.vm_info.attributes + if vert_mat.vm_info.attributes & USE_DEPTH_CUE: + material.attributes.add('USE_DEPTH_CUE') + if vert_mat.vm_info.attributes & ARGB_EMISSIVE_ONLY: + material.attributes.add('ARGB_EMISSIVE_ONLY') + if vert_mat.vm_info.attributes & COPY_SPECULAR_TO_DIFFUSE: + material.attributes.add('COPY_SPECULAR_TO_DIFFUSE') + if vert_mat.vm_info.attributes & DEPTH_CUE_TO_ALPHA: + material.attributes.add('DEPTH_CUE_TO_ALPHA') + + instance.inputs['Attributes'].default_value = attributes + + # TODO: translate those to shader properties + # floats: UPerSec, VPerSec, UScale, VScale, FPS, Speed, UCenter, VCenter, UAmp, UFreq, UPhase, VAmp, VFreq, VPhase, + # UStep, VStep, StepsPerSecond, Offset, Axis, UOffset, VOffset, ClampFix, UseReflect, Period, VPerScale, + # BumpRotation, BumpScale + # ints: Log1Width, Log2Width, Last(Frame) + + instance.inputs['VM_ARGS_0'].default_value = vert_mat.vm_args_0 + instance.inputs['VM_ARGS_0'].default_value = vert_mat.vm_args_1 + + instance.inputs['Diffuse'].default_value = vert_mat.vm_info.diffuse.to_vector_rgba() + instance.inputs['Ambient'].default_value = vert_mat.vm_info.ambient.to_vector_rgba() + instance.inputs['Specular'].default_value = vert_mat.vm_info.specular.to_vector_rgba() + instance.inputs['Emissive'].default_value = vert_mat.vm_info.emissive.to_vector_rgba() + instance.inputs['Shininess'].default_value = vert_mat.vm_info.shininess + instance.inputs['Opacity'].default_value = vert_mat.vm_info.shininess + instance.inputs['Translucency'].default_value = vert_mat.vm_info.shininess instance.inputs['DepthCompare'].default_value = shader.depth_compare instance.inputs['DepthMask'].default_value = shader.depth_mask @@ -58,9 +81,14 @@ def register(name): # create group inputs group_inputs = group.nodes.new('NodeGroupInput') group_inputs.location = (-350,0) + + group.inputs.new('NodeSocketMaterialAttributes', 'Attributes') + group.inputs.new('NodeSocketSurfaceType', 'Surface type') + group.inputs.new('NodeSocketString', 'VM_ARGS_0') + group.inputs.new('NodeSocketString', 'VM_ARGS_1') group.inputs.new('NodeSocketColor', 'Diffuse') group.inputs['Diffuse'].default_value = (0.8, 0.8, 0.8, 1.0) - group.inputs.new('NodeSocketColor', 'DiffuseTexture') + group.inputs.new('NodeSocketTexture', 'DiffuseTexture') group.inputs.new('NodeSocketFloat', 'DiffuseTextureAlpha') group.inputs['DiffuseTextureAlpha'].default_value = 0.0 VertexMaterialGroup.addInputInt(group, 'DestBlend', max=1) diff --git a/io_mesh_w3d/common/utils/box_import.py b/io_mesh_w3d/common/utils/box_import.py index ed1aba4a..e036840e 100644 --- a/io_mesh_w3d/common/utils/box_import.py +++ b/io_mesh_w3d/common/utils/box_import.py @@ -19,7 +19,7 @@ def create_box(box, hlod, hierarchy, rig, coll): cube.from_pydata(verts, [], faces) cube.update(calc_edges=True) box_object = bpy.data.objects.new(box.name(), cube) - box_object.object_type = 'BOX' + #box_object.object_type = 'BOX' box_object.display_type = 'WIRE' mat = bpy.data.materials.new(box.name() + ".Material") diff --git a/io_mesh_w3d/common/utils/material_export.py b/io_mesh_w3d/common/utils/material_export.py index a04f52f0..9aad2c21 100644 --- a/io_mesh_w3d/common/utils/material_export.py +++ b/io_mesh_w3d/common/utils/material_export.py @@ -43,6 +43,8 @@ def retrieve_material(context, mesh, material, tx_coords): def retrieve_vertex_material(context, material, shader_node): node_tree = material.node_tree + print(get_value(context, node_tree, shader_node.inputs['Translucency'], float)) + info = VertexMaterialInfo( attributes=0, shininess=material.specular_intensity, @@ -53,20 +55,20 @@ def retrieve_vertex_material(context, material, shader_node): translucency=get_value(context, node_tree, shader_node.inputs['Translucency'], float), opacity=get_value(context, node_tree, shader_node.inputs['Opacity'], float)) - if 'USE_DEPTH_CUE' in material.attributes: - info.attributes |= USE_DEPTH_CUE - if 'ARGB_EMISSIVE_ONLY' in material.attributes: - info.attributes |= ARGB_EMISSIVE_ONLY - if 'COPY_SPECULAR_TO_DIFFUSE' in material.attributes: - info.attributes |= COPY_SPECULAR_TO_DIFFUSE - if 'DEPTH_CUE_TO_ALPHA' in material.attributes: - info.attributes |= DEPTH_CUE_TO_ALPHA + #if 'USE_DEPTH_CUE' in material.attributes: + # info.attributes |= USE_DEPTH_CUE + #if 'ARGB_EMISSIVE_ONLY' in material.attributes: + # info.attributes |= ARGB_EMISSIVE_ONLY + #if 'COPY_SPECULAR_TO_DIFFUSE' in material.attributes: + # info.attributes |= COPY_SPECULAR_TO_DIFFUSE + #if 'DEPTH_CUE_TO_ALPHA' in material.attributes: + # info.attributes |= DEPTH_CUE_TO_ALPHA vert_mat = VertexMaterial() vert_mat.vm_name = shader_node.label vert_mat.vm_info = info - vert_mat.vm_args_0 = material.vm_args_0 - vert_mat.vm_args_1 = material.vm_args_1 + #vert_mat.vm_args_0 = material.vm_args_0 + #vert_mat.vm_args_1 = material.vm_args_1 shader = Shader( depth_compare=get_value(context, node_tree, shader_node.inputs['DepthCompare'], int), diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index 3ade2455..cc23a22e 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -5,7 +5,7 @@ import bmesh from bpy_extras import node_shader_utils -from io_mesh_w3d.common.node_groups.vertex_material import * +from io_mesh_w3d.common.shading.vertex_material_group import * from io_mesh_w3d.common.utils.helpers import * from io_mesh_w3d.w3d.structs.mesh_structs.vertex_material import * from io_mesh_w3d.common.structs.mesh_structs.shader_material import * @@ -68,32 +68,12 @@ def create_vertex_material(context, mesh, b_mesh, triangles, vert_mat, shader, t material.blend_method = 'BLEND' material.show_transparent_back = False - material.attributes = {'DEFAULT'} - attributes = vert_mat.vm_info.attributes - if attributes & USE_DEPTH_CUE: - material.attributes.add('USE_DEPTH_CUE') - if attributes & ARGB_EMISSIVE_ONLY: - material.attributes.add('ARGB_EMISSIVE_ONLY') - if attributes & COPY_SPECULAR_TO_DIFFUSE: - material.attributes.add('COPY_SPECULAR_TO_DIFFUSE') - if attributes & DEPTH_CUE_TO_ALPHA: - material.attributes.add('DEPTH_CUE_TO_ALPHA') - - # TODO: translate those to shader properties - # floats: UPerSec, VPerSec, UScale, VScale, FPS, Speed, UCenter, VCenter, UAmp, UFreq, UPhase, VAmp, VFreq, VPhase, - # UStep, VStep, StepsPerSecond, Offset, Axis, UOffset, VOffset, ClampFix, UseReflect, Period, VPerScale, - # BumpRotation, BumpScale - # ints: Log1Width, Log2Width, Last(Frame) - - material.vm_args_0 = vert_mat.vm_args_0 - material.vm_args_1 = vert_mat.vm_args_1 - node_tree = material.node_tree links = node_tree.links node_tree.nodes.remove(node_tree.nodes.get('Principled BSDF')) - instance = VertexMaterialGroup.create(node_tree, vert_mat.vm_name, vert_mat.vm_info, shader) + instance = VertexMaterialGroup.create(node_tree, vert_mat, shader) instance.label = vert_mat.vm_name instance.location = (0, 300) instance.width = 200 diff --git a/io_mesh_w3d/common/utils/mesh_import.py b/io_mesh_w3d/common/utils/mesh_import.py index 30238c7e..8ed93ad1 100644 --- a/io_mesh_w3d/common/utils/mesh_import.py +++ b/io_mesh_w3d/common/utils/mesh_import.py @@ -21,8 +21,8 @@ def create_mesh(context, mesh_struct, coll): mesh.validate() mesh_ob = bpy.data.objects.new(mesh_struct.name(), mesh) - mesh_ob.object_type = 'NORMAL' - mesh_ob.userText = mesh_struct.user_text + #mesh_ob.object_type = 'NORMAL' + #mesh_ob.userText = mesh_struct.user_text mesh_ob.use_empty_image_alpha = True link_object_to_active_scene(mesh_ob, coll) diff --git a/io_mesh_w3d/common/utils/node_group_creator.py b/io_mesh_w3d/common/utils/node_group_creator.py index fea0aeb7..125951c8 100644 --- a/io_mesh_w3d/common/utils/node_group_creator.py +++ b/io_mesh_w3d/common/utils/node_group_creator.py @@ -64,24 +64,11 @@ def process_presets(self, socket, xml_node, name=None): self.process_max_value(socket, xml_node.get('max')) - def map_custom_type_to_blender_type(self, type): - if type in ['NodeSocketTexture', 'NodeSocketVector4']: - return 'NodeSocketColor' - if type == 'NodeSocketTextureAlpha': - return 'NodeSocketFloat' - if type == 'NodeSocketVector2': - return 'NodeSocketVector' - if type == 'NodeSocketByte': - return 'NodeSocketInt' - return type - - def create_input_node(self, node_tree, xml_node, node): for child_node in xml_node: if child_node.tag != 'input': continue type = child_node.get('type') - type = self.map_custom_type_to_blender_type(type) name = child_node.get('name') socket = node_tree.inputs.new(type, name) diff --git a/io_mesh_w3d/custom_properties.py b/io_mesh_w3d/custom_properties.py index b6964c9d..40fde49e 100644 --- a/io_mesh_w3d/custom_properties.py +++ b/io_mesh_w3d/custom_properties.py @@ -3,18 +3,70 @@ import bpy from bpy.props import * -from bpy.types import Panel, Object, Material, PropertyGroup, Bone +from bpy.types import Mesh, Bone, MeshPolygon, NodeSocket + + +NodeSocket.presets = CollectionProperty( + type=None, + name="", + description="", + options={'ANIMATABLE'}, + tags={}) + ########################################################################## -# Object +# Mesh ########################################################################## -Object.userText = StringProperty( + +MeshPolygon.surface_type = EnumProperty( + name="Surface type", + description="Describes the surface type for this face", + items=[ + ('0', 'LightMetal', 'desc: todo'), + ('1', 'HeavyMetal', 'desc: todo'), + ('2', 'Water', 'desc: todo'), + ('3', 'Sand', 'desc: todo'), + ('4', 'Dirt', 'desc: todo'), + ('5', 'Mud', 'desc: todo'), + ('6', 'Grass', 'desc: todo'), + ('7', 'Wood', 'desc: todo'), + ('8', 'Concrete', 'desc: todo'), + ('9', 'Flesh', 'desc: todo'), + ('10', 'Rock', 'desc: todo'), + ('11', 'Snow', 'desc: todo'), + ('12', 'Ice', 'desc: todo'), + ('13', 'Default', 'desc: todo'), + ('14', 'Glass', 'desc: todo'), + ('15', 'Cloth', 'desc: todo'), + ('16', 'TiberiumField', 'desc: todo'), + ('17', 'FoliagePermeable', 'desc: todo'), + ('18', 'GlassPermeable', 'desc: todo'), + ('19', 'IcePermeable', 'desc: todo'), + ('20', 'ClothPermeable', 'desc: todo'), + ('21', 'Electrical', 'desc: todo'), + ('22', 'Flammable', 'desc: todo'), + ('23', 'Steam', 'desc: todo'), + ('24', 'ElectricalPermeable', 'desc: todo'), + ('25', 'FlammablePermeable', 'desc: todo'), + ('26', 'SteamPermeable', 'desc: todo'), + ('27', 'WaterPermeable', 'desc: todo'), + ('28', 'TiberiumWater', 'desc: todo'), + ('29', 'TiberiumWaterPermeable', 'desc: todo'), + ('30', 'UnderwaterDirt', 'desc: todo'), + ('31', 'UnderwaterTiberiumDirt', 'desc: todo')], + default='13') + +########################################################################## +# Mesh +########################################################################## + +Mesh.userText = StringProperty( name='User Text', description='This is a text defined by the user', default='') -Object.object_type = EnumProperty( +Mesh.object_type = EnumProperty( name='Type', description='Attributes that define the type of this object', items=[ @@ -23,7 +75,7 @@ ('DAZZLE', 'Dazzle', 'desc: todo')], default='NORMAL') -Object.dazzle_type = EnumProperty( +Mesh.dazzle_type = EnumProperty( name='Dazzle Type', description='defines the dazzle type', items=[ @@ -50,67 +102,3 @@ default=1.0, min=0.0, max=1.0, description='Visibility property') - -########################################################################## -# Material -########################################################################## - -Material.attributes = EnumProperty( - name='attributes', - description='Attributes that define the behaviour of this material', - items=[ - ('DEFAULT', 'Default', 'desc: todo', 0), - ('USE_DEPTH_CUE', 'UseDepthCue', 'desc: todo', 1), - ('ARGB_EMISSIVE_ONLY', 'ArgbEmissiveOnly', 'desc: todo', 2), - ('COPY_SPECULAR_TO_DIFFUSE', 'CopySpecularToDiffuse', 'desc: todo', 4), - ('DEPTH_CUE_TO_ALPHA', 'DepthCueToAlpha', 'desc: todo', 8)], - default=set(), - options={'ENUM_FLAG'}) - -Material.surface_type = EnumProperty( - name='Surface type', - description='Describes the surface type for this material', - items=[ - ('0', 'LightMetal', 'desc: todo'), - ('1', 'HeavyMetal', 'desc: todo'), - ('2', 'Water', 'desc: todo'), - ('3', 'Sand', 'desc: todo'), - ('4', 'Dirt', 'desc: todo'), - ('5', 'Mud', 'desc: todo'), - ('6', 'Grass', 'desc: todo'), - ('7', 'Wood', 'desc: todo'), - ('8', 'Concrete', 'desc: todo'), - ('9', 'Flesh', 'desc: todo'), - ('10', 'Rock', 'desc: todo'), - ('11', 'Snow', 'desc: todo'), - ('12', 'Ice', 'desc: todo'), - ('13', 'Default', 'desc: todo'), - ('14', 'Glass', 'desc: todo'), - ('15', 'Cloth', 'desc: todo'), - ('16', 'TiberiumField', 'desc: todo'), - ('17', 'FoliagePermeable', 'desc: todo'), - ('18', 'GlassPermeable', 'desc: todo'), - ('19', 'IcePermeable', 'desc: todo'), - ('20', 'ClothPermeable', 'desc: todo'), - ('21', 'Electrical', 'desc: todo'), - ('22', 'Flammable', 'desc: todo'), - ('23', 'Steam', 'desc: todo'), - ('24', 'ElectricalPermeable', 'desc: todo'), - ('25', 'FlammablePermeable', 'desc: todo'), - ('26', 'SteamPermeable', 'desc: todo'), - ('27', 'WaterPermeable', 'desc: todo'), - ('28', 'TiberiumWater', 'desc: todo'), - ('29', 'TiberiumWaterPermeable', 'desc: todo'), - ('30', 'UnderwaterDirt', 'desc: todo'), - ('31', 'UnderwaterTiberiumDirt', 'desc: todo')], - default='13') - -Material.vm_args_0 = StringProperty( - name='vm_args_0', - description='Vertex Material Arguments 0', - default='') - -Material.vm_args_1 = StringProperty( - name='vm_args_1', - description='Vertex Material Arguments 1', - default='') \ No newline at end of file From 0b22f4f22c9900966b13386bbd1629d4ecfac041 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Wed, 15 Apr 2020 22:25:39 +0200 Subject: [PATCH 45/62] some changes to material import --- io_mesh_w3d/__init__.py | 12 +++++----- .../common/shading/node_socket_enum.py | 4 ++-- .../shading/node_socket_texture_alpha.py | 4 ++-- .../common/shading/vertex_material_group.py | 5 ++-- .../common/utils/node_group_creator.py | 24 +++++++++++-------- io_mesh_w3d/custom_properties.py | 14 +++-------- 6 files changed, 29 insertions(+), 34 deletions(-) diff --git a/io_mesh_w3d/__init__.py b/io_mesh_w3d/__init__.py index ba4aed14..3c68c57b 100644 --- a/io_mesh_w3d/__init__.py +++ b/io_mesh_w3d/__init__.py @@ -257,17 +257,17 @@ def draw(self, context): col.prop(context.active_bone, 'visibility') -class MESH_POLYGON_PROPERTIES_PANEL_PT_w3d(Panel): +class MATERIAL_PROPERTIES_PANEL_PT_w3d(Panel): bl_label = 'W3D Properties' bl_space_type = 'PROPERTIES' - bl_region_type = 'PANEL' - bl_context = 'mesh polygon' + bl_region_type = 'WINDOW' + bl_context = 'material' def draw(self, context): layout = self.layout - if context.active_polygon is not None: - col = layout.column() - col.prop(context.active_bone, 'visibility') + mat = context.object.active_material + col = layout.column() + col.prop(mat, 'surface_type') import nodeitems_utils diff --git a/io_mesh_w3d/common/shading/node_socket_enum.py b/io_mesh_w3d/common/shading/node_socket_enum.py index 41a30961..d82c9a6f 100644 --- a/io_mesh_w3d/common/shading/node_socket_enum.py +++ b/io_mesh_w3d/common/shading/node_socket_enum.py @@ -2,10 +2,10 @@ # Written by Stephan Vedder and Michael Schnabel import bpy -from bpy.types import NodeSocket +from bpy.types import NodeSocketInt, NodeSocketInterfaceInt -class NodeSocketEnum(NodeSocket): +class NodeSocketEnum(NodeSocketInt, metaclass=NodeSocketInterfaceInt): bl_idname = 'NodeSocketEnum' bl_label = 'Enum Node Socket' diff --git a/io_mesh_w3d/common/shading/node_socket_texture_alpha.py b/io_mesh_w3d/common/shading/node_socket_texture_alpha.py index 465258c2..141e1a01 100644 --- a/io_mesh_w3d/common/shading/node_socket_texture_alpha.py +++ b/io_mesh_w3d/common/shading/node_socket_texture_alpha.py @@ -2,10 +2,10 @@ # Written by Stephan Vedder and Michael Schnabel import bpy -from bpy.types import NodeSocket +from bpy.types import NodeSocketFloat, NodeSocketInterfaceFloat -class NodeSocketTextureAlpha(NodeSocket): +class NodeSocketTextureAlpha(NodeSocketInterfaceFloat, NodeSocketFloat): bl_idname = 'NodeSocketTextureAlpha' bl_label = 'Texture Alpha Node Socket' diff --git a/io_mesh_w3d/common/shading/vertex_material_group.py b/io_mesh_w3d/common/shading/vertex_material_group.py index ac3ee3aa..b952d84c 100644 --- a/io_mesh_w3d/common/shading/vertex_material_group.py +++ b/io_mesh_w3d/common/shading/vertex_material_group.py @@ -83,14 +83,13 @@ def register(name): group_inputs.location = (-350,0) group.inputs.new('NodeSocketMaterialAttributes', 'Attributes') - group.inputs.new('NodeSocketSurfaceType', 'Surface type') group.inputs.new('NodeSocketString', 'VM_ARGS_0') group.inputs.new('NodeSocketString', 'VM_ARGS_1') group.inputs.new('NodeSocketColor', 'Diffuse') group.inputs['Diffuse'].default_value = (0.8, 0.8, 0.8, 1.0) group.inputs.new('NodeSocketTexture', 'DiffuseTexture') - group.inputs.new('NodeSocketFloat', 'DiffuseTextureAlpha') - group.inputs['DiffuseTextureAlpha'].default_value = 0.0 + group.inputs.new('NodeSocketTextureAlpha', 'DiffuseTextureAlpha') + # group.inputs['DiffuseTextureAlpha'].default_value = 0.0 VertexMaterialGroup.addInputInt(group, 'DestBlend', max=1) group.inputs.new('NodeSocketColor', 'Ambient') group.inputs['Ambient'].default_value = (0.8, 0.8, 0.8, 1.0) diff --git a/io_mesh_w3d/common/utils/node_group_creator.py b/io_mesh_w3d/common/utils/node_group_creator.py index 125951c8..73f47db0 100644 --- a/io_mesh_w3d/common/utils/node_group_creator.py +++ b/io_mesh_w3d/common/utils/node_group_creator.py @@ -20,18 +20,22 @@ def process_input_hides(self, xml_node, node): node.outputs[id].hide = True - def process_default_value(self, socket, default): + def process_default_value(self, socket, type, default): if default is None: return - if socket.type == 'VALUE': + if type in ['NodeSocketFloat', 'NodeSocketTextureAlpha']: default = float(default) - elif socket.type == 'INT': - default = int(default) - elif socket.type == 'BOOLEAN': + elif type == 'NodeSocketInt': default = int(default) - elif socket.type == 'RGBA': + elif type == 'NodeSocketBool': + default = default in ['True', 'true'] + elif type == 'NodeSocketColor': values = default.split(',') default = Vector((float(values[0]), float(values[1]), float(values[2]), float(values[3]))) + else: + print(type) + return + print(type) socket.default_value = default @@ -55,11 +59,11 @@ def process_max_value(self, socket, max): socket.max_value = max - def process_presets(self, socket, xml_node, name=None): + def process_presets(self, socket, type, xml_node, name=None): if name is None: name = xml_node.get('name', xml_node.get('id')) - self.process_default_value(socket, xml_node.get('default')) + self.process_default_value(socket, type, xml_node.get('default')) self.process_min_value(socket, xml_node.get('min')) self.process_max_value(socket, xml_node.get('max')) @@ -72,7 +76,7 @@ def create_input_node(self, node_tree, xml_node, node): name = child_node.get('name') socket = node_tree.inputs.new(type, name) - self.process_presets(socket, child_node, name) + self.process_presets(socket, type, child_node, name) def create_output_node(self, node_tree, xml_node, node): @@ -124,7 +128,7 @@ def create(self, directory, file, node_tree=None): self.create_output_node(node_tree, xml_node, node) elif type == 'ShaderNodeMath': node.operation = xml_node.get('mode').upper() - self.process_presets(node_tree, xml_node) + # self.process_presets(node_tree, type, xml_node) elif type in ['ShaderNodeEeveeSpecular', 'ShaderNodeNormalMap', 'ShaderNodeSeparateHSV']: continue else: diff --git a/io_mesh_w3d/custom_properties.py b/io_mesh_w3d/custom_properties.py index 40fde49e..0f851ea9 100644 --- a/io_mesh_w3d/custom_properties.py +++ b/io_mesh_w3d/custom_properties.py @@ -3,23 +3,15 @@ import bpy from bpy.props import * -from bpy.types import Mesh, Bone, MeshPolygon, NodeSocket - - -NodeSocket.presets = CollectionProperty( - type=None, - name="", - description="", - options={'ANIMATABLE'}, - tags={}) +from bpy.types import Mesh, Bone, Material ########################################################################## -# Mesh +# Material ########################################################################## -MeshPolygon.surface_type = EnumProperty( +Material.surface_type = EnumProperty( name="Surface type", description="Describes the surface type for this face", items=[ From 611f1d3cecafb71431933a1177a6801ed3b40801 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Fri, 17 Apr 2020 00:00:49 +0200 Subject: [PATCH 46/62] got custom node sockets somewhat working --- io_mesh_w3d/__init__.py | 117 ++++++++++++++++++ .../common/shading/node_socket_enum.py | 12 +- .../shading/node_socket_texture_alpha.py | 16 +-- .../common/shading/vertex_material_group.py | 10 +- .../common/utils/node_group_creator.py | 4 +- 5 files changed, 139 insertions(+), 20 deletions(-) diff --git a/io_mesh_w3d/__init__.py b/io_mesh_w3d/__init__.py index 3c68c57b..ef0961b7 100644 --- a/io_mesh_w3d/__init__.py +++ b/io_mesh_w3d/__init__.py @@ -270,6 +270,121 @@ def draw(self, context): col.prop(mat, 'surface_type') + +from bpy.types import NodeTree, Node, NodeSocket + + +# Custom socket type +class MyCustomSocket(NodeSocket): + # Description string + '''Custom node socket type''' + # Optional identifier string. If not explicitly defined, the python class name is used. + bl_idname = 'CustomSocketType' + # Label for nice name display + bl_label = "Custom Node Socket" + + # Enum items list + my_items = ( + ('DOWN', "Down", "Where your feet are"), + ('UP', "Up", "Where your head should be"), + ('LEFT', "Left", "Not right"), + ('RIGHT', "Right", "Not left"), + ) + + my_enum_prop: bpy.props.EnumProperty( + name="Direction", + description="Just an example", + items=my_items, + default='UP', + ) + + # Optional function for drawing the socket input value + def draw(self, context, layout, node, text): + if self.is_output or self.is_linked: + layout.label(text=text) + else: + layout.prop(self, "my_enum_prop", text=text) + + # Socket color + def draw_color(self, context, node): + return (1.0, 0.4, 0.216, 0.5) + + +# Mix-in class for all custom nodes in this tree type. +# Defines a poll function to enable instantiation. +class MyCustomTreeNode: + @classmethod + def poll(cls, ntree): + return ntree.bl_idname == 'CustomTreeType' + + +# Derived from the Node base type. +class MyCustomNode(Node, MyCustomTreeNode): + # === Basics === + # Description string + '''A custom node''' + # Optional identifier string. If not explicitly defined, the python class name is used. + bl_idname = 'CustomNodeType' + # Label for nice name display + bl_label = "Custom Node" + # Icon identifier + bl_icon = 'SOUND' + + # === Custom Properties === + # These work just like custom properties in ID data blocks + # Extensive information can be found under + # http://wiki.blender.org/index.php/Doc:2.6/Manual/Extensions/Python/Properties + my_string_prop: bpy.props.StringProperty() + my_float_prop: bpy.props.FloatProperty(default=3.1415926) + + # === Optional Functions === + # Initialization function, called when a new node is created. + # This is the most common place to create the sockets for a node, as shown below. + # NOTE: this is not the same as the standard __init__ function in Python, which is + # a purely internal Python method and unknown to the node system! + def init(self, context): + self.inputs.new('CustomSocketType', "Hello") + self.inputs['Hello'].my_enum_prop = 'LEFT' + self.inputs['Hello'].default_value = 'RIGHT' + self.inputs.new('NodeSocketFloat', "World") + self.inputs.new('NodeSocketVector', "!") + + self.outputs.new('NodeSocketColor', "How") + self.outputs.new('NodeSocketColor', "are") + self.outputs.new('NodeSocketFloat', "you") + + print('DONE') + + def update(self): + print('UPDATING') + #self.inputs['Hello'].my_enum_prop = 'DOWN' + + # Copy function to initialize a copied node from an existing one. + def copy(self, node): + print("Copying from node ", node) + + # Free function to clean up on removal. + def free(self): + print("Removing node ", self, ", Goodbye!") + + # Additional buttons displayed on the node. + def draw_buttons(self, context, layout): + layout.label(text="Node settings") + layout.prop(self, "my_float_prop") + + # Detail buttons in the sidebar. + # If this function is not defined, the draw_buttons function is used instead + def draw_buttons_ext(self, context, layout): + layout.prop(self, "my_float_prop") + # my_string_prop button will only be visible in the sidebar + layout.prop(self, "my_string_prop") + + # Optional: custom label + # Explicit user label overrides this, but here we can define a label dynamically + def draw_label(self): + return "I am a custom node" + + import nodeitems_utils from nodeitems_utils import NodeCategory, NodeItem @@ -305,6 +420,8 @@ def draw(self, context): CLASSES = ( + MyCustomSocket, + MyCustomNode, NodeSocketTexture, NodeSocketTextureAlpha, NodeSocketVector2, diff --git a/io_mesh_w3d/common/shading/node_socket_enum.py b/io_mesh_w3d/common/shading/node_socket_enum.py index d82c9a6f..c569c510 100644 --- a/io_mesh_w3d/common/shading/node_socket_enum.py +++ b/io_mesh_w3d/common/shading/node_socket_enum.py @@ -2,14 +2,14 @@ # Written by Stephan Vedder and Michael Schnabel import bpy -from bpy.types import NodeSocketInt, NodeSocketInterfaceInt +from bpy.types import NodeSocketInt -class NodeSocketEnum(NodeSocketInt, metaclass=NodeSocketInterfaceInt): +class NodeSocketEnum(NodeSocketInt): bl_idname = 'NodeSocketEnum' bl_label = 'Enum Node Socket' - my_enum_prop: bpy.props.EnumProperty( + default_value: bpy.props.EnumProperty( name="Direction", description="Just an example", items=[ @@ -23,16 +23,16 @@ def draw(self, context, layout, node, text): if self.is_output or self.is_linked: layout.label(text=text) else: - layout.prop(self, "my_enum_prop", text=text) + layout.prop(self, 'default_value', text=text) def draw_color(self, context, node): return (1.0, 0.4, 0.216, 0.5) class NodeSocketMaterialAttributes(NodeSocketEnum): bl_idname = 'NodeSocketMaterialAttributes' - bl_label = "Material Attributes Enum Flag Node Socket" + bl_label = 'Material Attributes Enum Flag Node Socket' - my_enum_prop: bpy.props.EnumProperty( + default_value: bpy.props.EnumProperty( name='Attributes', description='Attributes that define the behaviour of this material', items=[ diff --git a/io_mesh_w3d/common/shading/node_socket_texture_alpha.py b/io_mesh_w3d/common/shading/node_socket_texture_alpha.py index 141e1a01..1672a64d 100644 --- a/io_mesh_w3d/common/shading/node_socket_texture_alpha.py +++ b/io_mesh_w3d/common/shading/node_socket_texture_alpha.py @@ -2,24 +2,26 @@ # Written by Stephan Vedder and Michael Schnabel import bpy -from bpy.types import NodeSocketFloat, NodeSocketInterfaceFloat +from bpy.types import NodeSocketFloat -class NodeSocketTextureAlpha(NodeSocketInterfaceFloat, NodeSocketFloat): +class NodeSocketTextureAlpha(NodeSocketFloat): bl_idname = 'NodeSocketTextureAlpha' bl_label = 'Texture Alpha Node Socket' - float_prop: bpy.props.FloatProperty( + default_value: bpy.props.FloatProperty( name='Texture Alpha', - default=1.0, - min=0.0, max=1.0, - description='Texture alpha property') + description='the alpha value of a texture', + default=1.0) def draw(self, context, layout, node, text): if self.is_output or self.is_linked: layout.label(text=text) else: - layout.prop(self, "float_prop", text=text) + layout.prop(self, 'default_value', text=text) + + def draw(self, context, layout, node, text): + layout.label(text=text) def draw_color(self, context, node): return (1.0, 0.4, 0.216, 0.5) diff --git a/io_mesh_w3d/common/shading/vertex_material_group.py b/io_mesh_w3d/common/shading/vertex_material_group.py index b952d84c..960e5ac8 100644 --- a/io_mesh_w3d/common/shading/vertex_material_group.py +++ b/io_mesh_w3d/common/shading/vertex_material_group.py @@ -18,15 +18,14 @@ def create(node_tree, vert_mat, shader): instance.label = vert_mat.vm_name attributes = {'DEFAULT'} - attributes = vert_mat.vm_info.attributes if vert_mat.vm_info.attributes & USE_DEPTH_CUE: - material.attributes.add('USE_DEPTH_CUE') + attributes.add('USE_DEPTH_CUE') if vert_mat.vm_info.attributes & ARGB_EMISSIVE_ONLY: - material.attributes.add('ARGB_EMISSIVE_ONLY') + attributes.add('ARGB_EMISSIVE_ONLY') if vert_mat.vm_info.attributes & COPY_SPECULAR_TO_DIFFUSE: - material.attributes.add('COPY_SPECULAR_TO_DIFFUSE') + attributes.add('COPY_SPECULAR_TO_DIFFUSE') if vert_mat.vm_info.attributes & DEPTH_CUE_TO_ALPHA: - material.attributes.add('DEPTH_CUE_TO_ALPHA') + attributes.add('DEPTH_CUE_TO_ALPHA') instance.inputs['Attributes'].default_value = attributes @@ -89,7 +88,6 @@ def register(name): group.inputs['Diffuse'].default_value = (0.8, 0.8, 0.8, 1.0) group.inputs.new('NodeSocketTexture', 'DiffuseTexture') group.inputs.new('NodeSocketTextureAlpha', 'DiffuseTextureAlpha') - # group.inputs['DiffuseTextureAlpha'].default_value = 0.0 VertexMaterialGroup.addInputInt(group, 'DestBlend', max=1) group.inputs.new('NodeSocketColor', 'Ambient') group.inputs['Ambient'].default_value = (0.8, 0.8, 0.8, 1.0) diff --git a/io_mesh_w3d/common/utils/node_group_creator.py b/io_mesh_w3d/common/utils/node_group_creator.py index 73f47db0..28624a01 100644 --- a/io_mesh_w3d/common/utils/node_group_creator.py +++ b/io_mesh_w3d/common/utils/node_group_creator.py @@ -33,7 +33,6 @@ def process_default_value(self, socket, type, default): values = default.split(',') default = Vector((float(values[0]), float(values[1]), float(values[2]), float(values[3]))) else: - print(type) return print(type) socket.default_value = default @@ -75,6 +74,9 @@ def create_input_node(self, node_tree, xml_node, node): type = child_node.get('type') name = child_node.get('name') + if type == 'NodeSocketTextureAlpha': + type = 'NodeSocketFloat' + socket = node_tree.inputs.new(type, name) self.process_presets(socket, type, child_node, name) From 7a5b48b32bbdfdaa03f95d85c30188a7a34bad2d Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Fri, 17 Apr 2020 00:33:24 +0200 Subject: [PATCH 47/62] further improved custom node sockets --- io_mesh_w3d/__init__.py | 150 +----------------- .../common/utils/node_group_creator.py | 8 +- io_mesh_w3d/node_group_templates/BasicW3D.xml | 2 +- .../node_group_templates/DefaultW3D.xml | 4 +- io_mesh_w3d/node_group_templates/Infantry.xml | 4 +- .../node_group_templates/NormalMapped.xml | 2 +- version_history.txt | 1 + 7 files changed, 13 insertions(+), 158 deletions(-) diff --git a/io_mesh_w3d/__init__.py b/io_mesh_w3d/__init__.py index ef0961b7..5d468477 100644 --- a/io_mesh_w3d/__init__.py +++ b/io_mesh_w3d/__init__.py @@ -3,6 +3,7 @@ import os import bpy +from bpy.types import Panel from bpy_extras.io_utils import ImportHelper, ExportHelper from io_mesh_w3d.export_utils import save from io_mesh_w3d.custom_properties import * @@ -225,7 +226,6 @@ def menu_func_export(self, _context): def menu_func_import(self, _context): self.layout.operator(ImportW3D.bl_idname, text='Westwood W3D (.w3d/.w3x)') -from bpy.types import Panel class MESH_PROPERTIES_PANEL_PT_w3d(Panel): bl_label = 'W3D Properties' @@ -270,148 +270,6 @@ def draw(self, context): col.prop(mat, 'surface_type') - -from bpy.types import NodeTree, Node, NodeSocket - - -# Custom socket type -class MyCustomSocket(NodeSocket): - # Description string - '''Custom node socket type''' - # Optional identifier string. If not explicitly defined, the python class name is used. - bl_idname = 'CustomSocketType' - # Label for nice name display - bl_label = "Custom Node Socket" - - # Enum items list - my_items = ( - ('DOWN', "Down", "Where your feet are"), - ('UP', "Up", "Where your head should be"), - ('LEFT', "Left", "Not right"), - ('RIGHT', "Right", "Not left"), - ) - - my_enum_prop: bpy.props.EnumProperty( - name="Direction", - description="Just an example", - items=my_items, - default='UP', - ) - - # Optional function for drawing the socket input value - def draw(self, context, layout, node, text): - if self.is_output or self.is_linked: - layout.label(text=text) - else: - layout.prop(self, "my_enum_prop", text=text) - - # Socket color - def draw_color(self, context, node): - return (1.0, 0.4, 0.216, 0.5) - - -# Mix-in class for all custom nodes in this tree type. -# Defines a poll function to enable instantiation. -class MyCustomTreeNode: - @classmethod - def poll(cls, ntree): - return ntree.bl_idname == 'CustomTreeType' - - -# Derived from the Node base type. -class MyCustomNode(Node, MyCustomTreeNode): - # === Basics === - # Description string - '''A custom node''' - # Optional identifier string. If not explicitly defined, the python class name is used. - bl_idname = 'CustomNodeType' - # Label for nice name display - bl_label = "Custom Node" - # Icon identifier - bl_icon = 'SOUND' - - # === Custom Properties === - # These work just like custom properties in ID data blocks - # Extensive information can be found under - # http://wiki.blender.org/index.php/Doc:2.6/Manual/Extensions/Python/Properties - my_string_prop: bpy.props.StringProperty() - my_float_prop: bpy.props.FloatProperty(default=3.1415926) - - # === Optional Functions === - # Initialization function, called when a new node is created. - # This is the most common place to create the sockets for a node, as shown below. - # NOTE: this is not the same as the standard __init__ function in Python, which is - # a purely internal Python method and unknown to the node system! - def init(self, context): - self.inputs.new('CustomSocketType', "Hello") - self.inputs['Hello'].my_enum_prop = 'LEFT' - self.inputs['Hello'].default_value = 'RIGHT' - self.inputs.new('NodeSocketFloat', "World") - self.inputs.new('NodeSocketVector', "!") - - self.outputs.new('NodeSocketColor', "How") - self.outputs.new('NodeSocketColor', "are") - self.outputs.new('NodeSocketFloat', "you") - - print('DONE') - - def update(self): - print('UPDATING') - #self.inputs['Hello'].my_enum_prop = 'DOWN' - - # Copy function to initialize a copied node from an existing one. - def copy(self, node): - print("Copying from node ", node) - - # Free function to clean up on removal. - def free(self): - print("Removing node ", self, ", Goodbye!") - - # Additional buttons displayed on the node. - def draw_buttons(self, context, layout): - layout.label(text="Node settings") - layout.prop(self, "my_float_prop") - - # Detail buttons in the sidebar. - # If this function is not defined, the draw_buttons function is used instead - def draw_buttons_ext(self, context, layout): - layout.prop(self, "my_float_prop") - # my_string_prop button will only be visible in the sidebar - layout.prop(self, "my_string_prop") - - # Optional: custom label - # Explicit user label overrides this, but here we can define a label dynamically - def draw_label(self): - return "I am a custom node" - - -import nodeitems_utils -from nodeitems_utils import NodeCategory, NodeItem - -# all categories in a list -node_categories = [ - # identifier, label, items list - NodeCategory('SOMENODES', 'Some Nodes', items=[ - # our basic node - NodeItem('DecisionNode'), - ]), - NodeCategory('OTHERNODES', "Other Nodes", items=[ - # the node item can have additional settings, - # which are applied to new nodes - # NB: settings values are stored as string expressions, - # for this reason they should be converted to strings using repr() - NodeItem("CustomNodeType", label="Node A", settings={ - "my_string_prop": repr("Lorem ipsum dolor sit amet"), - "my_float_prop": repr(1.0), - }), - NodeItem("CustomNodeType", label="Node B", settings={ - "my_string_prop": repr("consectetur adipisicing elit"), - "my_float_prop": repr(2.0), - }), - ]), -] - - from io_mesh_w3d.common.shading.node_socket_texture import NodeSocketTexture from io_mesh_w3d.common.shading.node_socket_texture_alpha import NodeSocketTextureAlpha from io_mesh_w3d.common.shading.node_socket_vec2 import NodeSocketVector2 @@ -420,8 +278,6 @@ def draw_label(self): CLASSES = ( - MyCustomSocket, - MyCustomNode, NodeSocketTexture, NodeSocketTextureAlpha, NodeSocketVector2, @@ -432,6 +288,7 @@ def draw_label(self): MESH_PROPERTIES_PANEL_PT_w3d, BONE_PROPERTIES_PANEL_PT_w3d) + def register_node_groups(): from io_mesh_w3d.common.utils.node_group_creator import NodeGroupCreator dirname = os.path.dirname(__file__) @@ -445,12 +302,11 @@ def register_node_groups(): from io_mesh_w3d.common.shading.vertex_material_group import VertexMaterialGroup VertexMaterialGroup.register(VertexMaterialGroup.name) + def register(): for class_ in CLASSES: bpy.utils.register_class(class_) - nodeitems_utils.register_node_categories('CUSTOM_NODES', node_categories) - bpy.types.TOPBAR_MT_file_import.append(menu_func_import) bpy.types.TOPBAR_MT_file_export.append(menu_func_export) diff --git a/io_mesh_w3d/common/utils/node_group_creator.py b/io_mesh_w3d/common/utils/node_group_creator.py index 28624a01..2611ab23 100644 --- a/io_mesh_w3d/common/utils/node_group_creator.py +++ b/io_mesh_w3d/common/utils/node_group_creator.py @@ -23,7 +23,7 @@ def process_input_hides(self, xml_node, node): def process_default_value(self, socket, type, default): if default is None: return - if type in ['NodeSocketFloat', 'NodeSocketTextureAlpha']: + if type in ['NodeSocketFloat']: default = float(default) elif type == 'NodeSocketInt': default = int(default) @@ -33,8 +33,9 @@ def process_default_value(self, socket, type, default): values = default.split(',') default = Vector((float(values[0]), float(values[1]), float(values[2]), float(values[3]))) else: + print('INFO: default value for NodeSocket ' + type + ' not supported') return - print(type) + socket.default_value = default @@ -74,9 +75,6 @@ def create_input_node(self, node_tree, xml_node, node): type = child_node.get('type') name = child_node.get('name') - if type == 'NodeSocketTextureAlpha': - type = 'NodeSocketFloat' - socket = node_tree.inputs.new(type, name) self.process_presets(socket, type, child_node, name) diff --git a/io_mesh_w3d/node_group_templates/BasicW3D.xml b/io_mesh_w3d/node_group_templates/BasicW3D.xml index 1c25cb86..71f0f598 100644 --- a/io_mesh_w3d/node_group_templates/BasicW3D.xml +++ b/io_mesh_w3d/node_group_templates/BasicW3D.xml @@ -5,7 +5,7 @@ - + diff --git a/io_mesh_w3d/node_group_templates/DefaultW3D.xml b/io_mesh_w3d/node_group_templates/DefaultW3D.xml index b464e713..94207c0b 100644 --- a/io_mesh_w3d/node_group_templates/DefaultW3D.xml +++ b/io_mesh_w3d/node_group_templates/DefaultW3D.xml @@ -5,9 +5,9 @@ - + - + diff --git a/io_mesh_w3d/node_group_templates/Infantry.xml b/io_mesh_w3d/node_group_templates/Infantry.xml index e24ac077..2e93699f 100644 --- a/io_mesh_w3d/node_group_templates/Infantry.xml +++ b/io_mesh_w3d/node_group_templates/Infantry.xml @@ -5,10 +5,10 @@ - + - + diff --git a/io_mesh_w3d/node_group_templates/NormalMapped.xml b/io_mesh_w3d/node_group_templates/NormalMapped.xml index 4c55166d..31bc24ce 100644 --- a/io_mesh_w3d/node_group_templates/NormalMapped.xml +++ b/io_mesh_w3d/node_group_templates/NormalMapped.xml @@ -5,7 +5,7 @@ - + LON diff --git a/version_history.txt b/version_history.txt index 273316d0..f27a4272 100644 --- a/version_history.txt +++ b/version_history.txt @@ -1,4 +1,5 @@ v0.4.6 +- support custom node sockets - support alpha values of textures - support for custom shaders via xml templates - support prelit materials and multiple material passes From 30483ffdf6b8ffe424cd11ed36ed0764a48d3f7e Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Fri, 17 Apr 2020 01:29:29 +0200 Subject: [PATCH 48/62] added surface type dict --- .../common/structs/mesh_structs/triangle.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/io_mesh_w3d/common/structs/mesh_structs/triangle.py b/io_mesh_w3d/common/structs/mesh_structs/triangle.py index f225306b..09148f76 100644 --- a/io_mesh_w3d/common/structs/mesh_structs/triangle.py +++ b/io_mesh_w3d/common/structs/mesh_structs/triangle.py @@ -6,6 +6,42 @@ from io_mesh_w3d.w3x.io_xml import * +surface_types = { + '0': 'LightMetal', + '1': 'HeavyMetal', + '2': 'Water', + '3': 'Sand', + '4': 'Dirt', + '5': 'Mud', + '6': 'Grass', + '7': 'Wood', + '8': 'Concrete', + '9': 'Flesh', + '10': 'Rock', + '11': 'Snow', + '12': 'Ice', + '13': 'Default', + '14': 'Glass', + '15': 'Cloth', + '16': 'TiberiumField', + '17': 'FoliagePermeable', + '18': 'GlassPermeable', + '19': 'IcePermeable', + '20': 'ClothPermeable', + '21': 'Electrical', + '22': 'Flammable', + '23': 'Steam', + '24': 'ElectricalPermeable', + '25': 'FlammablePermeable', + '26': 'SteamPermeable', + '27': 'WaterPermeable', + '28': 'TiberiumWater', + '29': 'TiberiumWaterPermeable', + '30': 'UnderwaterDirt', + '31': 'UnderwaterTiberiumDirt'} + + + class Triangle: def __init__(self, vert_ids=None, surface_type=13, normal=Vector((0.0, 0.0, 0.0)), distance=0.0): self.vert_ids = vert_ids if vert_ids is not None else [] From 24f0f16e3aabace271ad003c5b93dbfd1ba40204 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Fri, 17 Apr 2020 15:09:57 +0200 Subject: [PATCH 49/62] added custom decision node --- io_mesh_w3d/__init__.py | 18 +++++ io_mesh_w3d/common/shading/node_decision.py | 26 +++++++ .../common/structs/mesh_structs/triangle.py | 69 ++++++++++--------- io_mesh_w3d/common/utils/mesh_import.py | 15 ++-- 4 files changed, 91 insertions(+), 37 deletions(-) create mode 100644 io_mesh_w3d/common/shading/node_decision.py diff --git a/io_mesh_w3d/__init__.py b/io_mesh_w3d/__init__.py index 5d468477..82282b7b 100644 --- a/io_mesh_w3d/__init__.py +++ b/io_mesh_w3d/__init__.py @@ -270,11 +270,23 @@ def draw(self, context): col.prop(mat, 'surface_type') +import nodeitems_utils +from nodeitems_utils import NodeCategory, NodeItem + + +node_categories = [ + NodeCategory('W3D nodes', 'W3D nodes', items=[ + NodeItem('DecisionNode'), + ]) +] + + from io_mesh_w3d.common.shading.node_socket_texture import NodeSocketTexture from io_mesh_w3d.common.shading.node_socket_texture_alpha import NodeSocketTextureAlpha from io_mesh_w3d.common.shading.node_socket_vec2 import NodeSocketVector2 from io_mesh_w3d.common.shading.node_socket_vec4 import NodeSocketVector4 from io_mesh_w3d.common.shading.node_socket_enum import NodeSocketMaterialAttributes +from io_mesh_w3d.common.shading.node_decision import DecisionNode CLASSES = ( @@ -283,6 +295,7 @@ def draw(self, context): NodeSocketVector2, NodeSocketVector4, NodeSocketMaterialAttributes, + DecisionNode, ExportW3D, ImportW3D, MESH_PROPERTIES_PANEL_PT_w3d, @@ -307,6 +320,8 @@ def register(): for class_ in CLASSES: bpy.utils.register_class(class_) + nodeitems_utils.register_node_categories('CUSTOM_NODES', node_categories) + bpy.types.TOPBAR_MT_file_import.append(menu_func_import) bpy.types.TOPBAR_MT_file_export.append(menu_func_export) @@ -323,6 +338,9 @@ def unregister(): for class_ in reversed(CLASSES): bpy.utils.unregister_class(class_) + + nodeitems_utils.unregister_node_categories('CUSTOM_NODES') + bpy.types.TOPBAR_MT_file_import.remove(menu_func_import) bpy.types.TOPBAR_MT_file_export.remove(menu_func_export) diff --git a/io_mesh_w3d/common/shading/node_decision.py b/io_mesh_w3d/common/shading/node_decision.py new file mode 100644 index 00000000..e42fdc0b --- /dev/null +++ b/io_mesh_w3d/common/shading/node_decision.py @@ -0,0 +1,26 @@ +# +# Written by Stephan Vedder and Michael Schnabel + +import bpy +from bpy.types import Node + + +class DecisionNode(Node): + bl_idname = 'DecisionNode' + bl_label = 'Decision Node' + + def init(self, context): + self.inputs.new('NodeSocketBool', 'decide') + self.inputs.new('NodeSocketFloat', 'value1') + self.inputs.new('NodeSocketFloat', 'value2') + + self.outputs.new('NodeSocketFloat', 'value') + + def copy(self, node): + print('Copying from node ', node) + + def free(self): + print('Removing node ', self, ', Goodbye!') + + def draw_label(self): + return 'Decision' \ No newline at end of file diff --git a/io_mesh_w3d/common/structs/mesh_structs/triangle.py b/io_mesh_w3d/common/structs/mesh_structs/triangle.py index 09148f76..dd35a02f 100644 --- a/io_mesh_w3d/common/structs/mesh_structs/triangle.py +++ b/io_mesh_w3d/common/structs/mesh_structs/triangle.py @@ -6,39 +6,39 @@ from io_mesh_w3d.w3x.io_xml import * -surface_types = { - '0': 'LightMetal', - '1': 'HeavyMetal', - '2': 'Water', - '3': 'Sand', - '4': 'Dirt', - '5': 'Mud', - '6': 'Grass', - '7': 'Wood', - '8': 'Concrete', - '9': 'Flesh', - '10': 'Rock', - '11': 'Snow', - '12': 'Ice', - '13': 'Default', - '14': 'Glass', - '15': 'Cloth', - '16': 'TiberiumField', - '17': 'FoliagePermeable', - '18': 'GlassPermeable', - '19': 'IcePermeable', - '20': 'ClothPermeable', - '21': 'Electrical', - '22': 'Flammable', - '23': 'Steam', - '24': 'ElectricalPermeable', - '25': 'FlammablePermeable', - '26': 'SteamPermeable', - '27': 'WaterPermeable', - '28': 'TiberiumWater', - '29': 'TiberiumWaterPermeable', - '30': 'UnderwaterDirt', - '31': 'UnderwaterTiberiumDirt'} +surface_types = [ + 'LightMetal', + 'HeavyMetal', + 'Water', + 'Sand', + 'Dirt', + 'Mud', + 'Grass', + 'Wood', + 'Concrete', + 'Flesh', + 'Rock', + 'Snow', + 'Ice', + 'Default', + 'Glass', + 'Cloth', + 'TiberiumField', + 'FoliagePermeable', + 'GlassPermeable', + 'IcePermeable', + 'ClothPermeable', + 'Electrical', + 'Flammable', + 'Steam', + 'ElectricalPermeable', + 'FlammablePermeable', + 'SteamPermeable', + 'WaterPermeable', + 'TiberiumWater', + 'TiberiumWaterPermeable', + 'UnderwaterDirt', + 'UnderwaterTiberiumDirt'] @@ -49,6 +49,9 @@ def __init__(self, vert_ids=None, surface_type=13, normal=Vector((0.0, 0.0, 0.0) self.normal = normal self.distance = distance + def get_surface_type_name(self): + return surface_types[self.surface_type] + @staticmethod def read(io_stream): return Triangle( diff --git a/io_mesh_w3d/common/utils/mesh_import.py b/io_mesh_w3d/common/utils/mesh_import.py index 8ed93ad1..47c6be9c 100644 --- a/io_mesh_w3d/common/utils/mesh_import.py +++ b/io_mesh_w3d/common/utils/mesh_import.py @@ -15,10 +15,10 @@ def create_mesh(context, mesh_struct, coll): mesh.from_pydata(mesh_struct.verts, [], triangles) mesh.normals_split_custom_set_from_vertices(mesh_struct.normals) - mesh.use_auto_smooth = True + #mesh.use_auto_smooth = True - mesh.update() - mesh.validate() + #mesh.update() + #mesh.validate() mesh_ob = bpy.data.objects.new(mesh_struct.name(), mesh) #mesh_ob.object_type = 'NORMAL' @@ -27,6 +27,14 @@ def create_mesh(context, mesh_struct, coll): link_object_to_active_scene(mesh_ob, coll) + # TODO: fix this and implement export + for i, triangle in enumerate(mesh_struct.triangles): + surface_type_name = triangle.get_surface_type_name() + if surface_type_name not in mesh_ob.face_maps: + mesh_ob.face_maps.new(name=surface_type_name) + + mesh_ob.face_maps[surface_type_name].add(triangle.vert_ids) + if mesh_struct.is_hidden(): mesh_ob.hide_set(True) @@ -75,7 +83,6 @@ def rig_mesh(mesh_struct, hierarchy, rig, sub_object=None): modifier.use_vertex_groups = True mesh.normals_split_custom_set_from_vertices(normals) - mesh.use_auto_smooth = True mesh.update() mesh.validate() From 6cb90608d58d6c96e24256987c1157be0259f57d Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Sat, 18 Apr 2020 17:37:38 +0200 Subject: [PATCH 50/62] fixed face map creation, moved custom properties from object to mesh --- io_mesh_w3d/__init__.py | 28 +++++----------- io_mesh_w3d/common/utils/mesh_import.py | 13 +++----- io_mesh_w3d/custom_properties.py | 43 ------------------------- 3 files changed, 13 insertions(+), 71 deletions(-) diff --git a/io_mesh_w3d/__init__.py b/io_mesh_w3d/__init__.py index 82282b7b..d2f5fe1a 100644 --- a/io_mesh_w3d/__init__.py +++ b/io_mesh_w3d/__init__.py @@ -231,17 +231,18 @@ class MESH_PROPERTIES_PANEL_PT_w3d(Panel): bl_label = 'W3D Properties' bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' - bl_context = 'mesh' + bl_context = 'data' def draw(self, context): layout = self.layout col = layout.column() - col.prop(context.active_object, 'object_type') - if context.active_object.object_type == 'DAZZLE': + mesh = context.active_object.data + col.prop(mesh, 'object_type') + if mesh.object_type == 'DAZZLE': col = layout.column() - col.prop(context.active_object, 'dazzle_type') + col.prop(mesh, 'dazzle_type') col = layout.column() - col.prop(context.active_object, 'userText') + col.prop(mesh, 'userText') class BONE_PROPERTIES_PANEL_PT_w3d(Panel): @@ -257,19 +258,6 @@ def draw(self, context): col.prop(context.active_bone, 'visibility') -class MATERIAL_PROPERTIES_PANEL_PT_w3d(Panel): - bl_label = 'W3D Properties' - bl_space_type = 'PROPERTIES' - bl_region_type = 'WINDOW' - bl_context = 'material' - - def draw(self, context): - layout = self.layout - mat = context.object.active_material - col = layout.column() - col.prop(mat, 'surface_type') - - import nodeitems_utils from nodeitems_utils import NodeCategory, NodeItem @@ -320,7 +308,7 @@ def register(): for class_ in CLASSES: bpy.utils.register_class(class_) - nodeitems_utils.register_node_categories('CUSTOM_NODES', node_categories) + #nodeitems_utils.register_node_categories('CUSTOM_NODES', node_categories) bpy.types.TOPBAR_MT_file_import.append(menu_func_import) bpy.types.TOPBAR_MT_file_export.append(menu_func_export) @@ -339,7 +327,7 @@ def unregister(): for class_ in reversed(CLASSES): bpy.utils.unregister_class(class_) - nodeitems_utils.unregister_node_categories('CUSTOM_NODES') + #nodeitems_utils.unregister_node_categories('CUSTOM_NODES') bpy.types.TOPBAR_MT_file_import.remove(menu_func_import) bpy.types.TOPBAR_MT_file_export.remove(menu_func_export) diff --git a/io_mesh_w3d/common/utils/mesh_import.py b/io_mesh_w3d/common/utils/mesh_import.py index 47c6be9c..73e4bcce 100644 --- a/io_mesh_w3d/common/utils/mesh_import.py +++ b/io_mesh_w3d/common/utils/mesh_import.py @@ -12,28 +12,25 @@ def create_mesh(context, mesh_struct, coll): triangles.append(tuple(triangle.vert_ids)) mesh = bpy.data.meshes.new(mesh_struct.name()) + mesh.userText = mesh_struct.user_text mesh.from_pydata(mesh_struct.verts, [], triangles) mesh.normals_split_custom_set_from_vertices(mesh_struct.normals) - #mesh.use_auto_smooth = True + mesh.use_auto_smooth = True - #mesh.update() - #mesh.validate() + mesh.update() + mesh.validate() mesh_ob = bpy.data.objects.new(mesh_struct.name(), mesh) - #mesh_ob.object_type = 'NORMAL' - #mesh_ob.userText = mesh_struct.user_text mesh_ob.use_empty_image_alpha = True link_object_to_active_scene(mesh_ob, coll) - # TODO: fix this and implement export for i, triangle in enumerate(mesh_struct.triangles): surface_type_name = triangle.get_surface_type_name() if surface_type_name not in mesh_ob.face_maps: mesh_ob.face_maps.new(name=surface_type_name) - - mesh_ob.face_maps[surface_type_name].add(triangle.vert_ids) + mesh_ob.face_maps[surface_type_name].add([i]) if mesh_struct.is_hidden(): mesh_ob.hide_set(True) diff --git a/io_mesh_w3d/custom_properties.py b/io_mesh_w3d/custom_properties.py index 0f851ea9..8b15e493 100644 --- a/io_mesh_w3d/custom_properties.py +++ b/io_mesh_w3d/custom_properties.py @@ -6,49 +6,6 @@ from bpy.types import Mesh, Bone, Material -########################################################################## -# Material -########################################################################## - - -Material.surface_type = EnumProperty( - name="Surface type", - description="Describes the surface type for this face", - items=[ - ('0', 'LightMetal', 'desc: todo'), - ('1', 'HeavyMetal', 'desc: todo'), - ('2', 'Water', 'desc: todo'), - ('3', 'Sand', 'desc: todo'), - ('4', 'Dirt', 'desc: todo'), - ('5', 'Mud', 'desc: todo'), - ('6', 'Grass', 'desc: todo'), - ('7', 'Wood', 'desc: todo'), - ('8', 'Concrete', 'desc: todo'), - ('9', 'Flesh', 'desc: todo'), - ('10', 'Rock', 'desc: todo'), - ('11', 'Snow', 'desc: todo'), - ('12', 'Ice', 'desc: todo'), - ('13', 'Default', 'desc: todo'), - ('14', 'Glass', 'desc: todo'), - ('15', 'Cloth', 'desc: todo'), - ('16', 'TiberiumField', 'desc: todo'), - ('17', 'FoliagePermeable', 'desc: todo'), - ('18', 'GlassPermeable', 'desc: todo'), - ('19', 'IcePermeable', 'desc: todo'), - ('20', 'ClothPermeable', 'desc: todo'), - ('21', 'Electrical', 'desc: todo'), - ('22', 'Flammable', 'desc: todo'), - ('23', 'Steam', 'desc: todo'), - ('24', 'ElectricalPermeable', 'desc: todo'), - ('25', 'FlammablePermeable', 'desc: todo'), - ('26', 'SteamPermeable', 'desc: todo'), - ('27', 'WaterPermeable', 'desc: todo'), - ('28', 'TiberiumWater', 'desc: todo'), - ('29', 'TiberiumWaterPermeable', 'desc: todo'), - ('30', 'UnderwaterDirt', 'desc: todo'), - ('31', 'UnderwaterTiberiumDirt', 'desc: todo')], - default='13') - ########################################################################## # Mesh ########################################################################## From baa9e2c65125f1b0e12d9fd6914b8c7bdbe27fc4 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Sat, 18 Apr 2020 17:49:30 +0200 Subject: [PATCH 51/62] apply not only x scale on export --- io_mesh_w3d/common/utils/box_export.py | 2 +- io_mesh_w3d/common/utils/hierarchy_export.py | 2 +- io_mesh_w3d/common/utils/hlod_export.py | 2 +- io_mesh_w3d/common/utils/mesh_export.py | 10 ++++++---- io_mesh_w3d/w3d/utils/dazzle_export.py | 2 +- version_history.txt | 1 + 6 files changed, 11 insertions(+), 8 deletions(-) diff --git a/io_mesh_w3d/common/utils/box_export.py b/io_mesh_w3d/common/utils/box_export.py index a9a9e822..1c1dd5bf 100644 --- a/io_mesh_w3d/common/utils/box_export.py +++ b/io_mesh_w3d/common/utils/box_export.py @@ -10,7 +10,7 @@ def retrieve_boxes(container_name): boxes = [] for mesh_object in get_objects('MESH'): - if mesh_object.object_type != 'BOX': + if mesh_object.data.object_type != 'BOX': continue name = container_name + '.' + mesh_object.name box = CollisionBox( diff --git a/io_mesh_w3d/common/utils/hierarchy_export.py b/io_mesh_w3d/common/utils/hierarchy_export.py index a0906043..8d103564 100644 --- a/io_mesh_w3d/common/utils/hierarchy_export.py +++ b/io_mesh_w3d/common/utils/hierarchy_export.py @@ -77,7 +77,7 @@ def retrieve_hierarchy(context, container_name): for mesh in list(reversed(meshes)): if mesh.vertex_groups \ - or mesh.object_type == 'BOX' \ + or mesh.data.object_type == 'BOX' \ or mesh.name in pick_plane_names: continue diff --git a/io_mesh_w3d/common/utils/hlod_export.py b/io_mesh_w3d/common/utils/hlod_export.py index 407e1929..ab57086b 100644 --- a/io_mesh_w3d/common/utils/hlod_export.py +++ b/io_mesh_w3d/common/utils/hlod_export.py @@ -25,7 +25,7 @@ def create_lod_array(meshes, hierarchy, container_name, lod_arrays): name=mesh.name, identifier=container_name + '.' + mesh.name, bone_index=0, - is_box=mesh.object_type == 'BOX') + is_box=mesh.data.object_type == 'BOX') if not mesh.vertex_groups: for index, pivot in enumerate(hierarchy.pivots): diff --git a/io_mesh_w3d/common/utils/mesh_export.py b/io_mesh_w3d/common/utils/mesh_export.py index 573a0a11..d02c3a64 100644 --- a/io_mesh_w3d/common/utils/mesh_export.py +++ b/io_mesh_w3d/common/utils/mesh_export.py @@ -20,7 +20,7 @@ def retrieve_meshes(context, hierarchy, rig, container_name, force_vertex_materi depsgraph = bpy.context.evaluated_depsgraph_get() for mesh_object in get_objects('MESH'): - if mesh_object.object_type != 'NORMAL': + if mesh_object.data.object_type != 'NORMAL': continue if mesh_object.mode != 'OBJECT': @@ -32,7 +32,7 @@ def retrieve_meshes(context, hierarchy, rig, container_name, force_vertex_materi container_name=container_name) header = mesh_struct.header - mesh_struct.user_text = mesh_object.userText + mesh_struct.user_text = mesh_object.data.userText if mesh_object.hide_get(): header.attrs |= GEOMETRY_TYPE_HIDDEN @@ -78,8 +78,10 @@ def retrieve_meshes(context, hierarchy, rig, container_name, force_vertex_materi context.warning('max 2 bone influences per vertex supported!') (_, _, scale) = mesh_object.matrix_local.decompose() - scaled_vert = vertex.co * scale.x - mesh_struct.verts.append(matrix @ scaled_vert) + vertex.co.x *= scale.x + vertex.co.y *= scale.y + vertex.co.z *= scale.z + mesh_struct.verts.append(matrix @ vertex.co) (_, rotation, _) = matrix.decompose() diff --git a/io_mesh_w3d/w3d/utils/dazzle_export.py b/io_mesh_w3d/w3d/utils/dazzle_export.py index 9de7b90c..6d2a941c 100644 --- a/io_mesh_w3d/w3d/utils/dazzle_export.py +++ b/io_mesh_w3d/w3d/utils/dazzle_export.py @@ -9,7 +9,7 @@ def retrieve_dazzles(container_name): dazzles = [] for mesh_object in get_objects('MESH'): - if mesh_object.object_type != 'DAZZLE': + if mesh_object.data.object_type != 'DAZZLE': continue name = container_name + '.' + mesh_object.name dazzle = Dazzle( diff --git a/version_history.txt b/version_history.txt index f27a4272..2f1ff422 100644 --- a/version_history.txt +++ b/version_history.txt @@ -4,6 +4,7 @@ v0.4.6 - support for custom shaders via xml templates - support prelit materials and multiple material passes - support for per face materials +- support for per face surface types via face maps - support for vertex colors - apply modifiers to meshes on export - handle export of 'multi-user' meshes From 4517ecfb838fde572b3198dd1519f062600cb3f5 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Sat, 18 Apr 2020 18:36:17 +0200 Subject: [PATCH 52/62] set triangle surface type depending on corresponding face map --- .../common/structs/mesh_structs/triangle.py | 12 +++- io_mesh_w3d/common/utils/mesh_export.py | 72 ++++--------------- 2 files changed, 25 insertions(+), 59 deletions(-) diff --git a/io_mesh_w3d/common/structs/mesh_structs/triangle.py b/io_mesh_w3d/common/structs/mesh_structs/triangle.py index dd35a02f..da9d2b14 100644 --- a/io_mesh_w3d/common/structs/mesh_structs/triangle.py +++ b/io_mesh_w3d/common/structs/mesh_structs/triangle.py @@ -41,7 +41,6 @@ 'UnderwaterTiberiumDirt'] - class Triangle: def __init__(self, vert_ids=None, surface_type=13, normal=Vector((0.0, 0.0, 0.0)), distance=0.0): self.vert_ids = vert_ids if vert_ids is not None else [] @@ -49,9 +48,20 @@ def __init__(self, vert_ids=None, surface_type=13, normal=Vector((0.0, 0.0, 0.0) self.normal = normal self.distance = distance + @staticmethod + def validate_face_map_names(context, face_map_names): + for name in face_map_names: + if not name in surface_types: + context.warning('name of face map: ' + name + ' is not one of valid surface types ' + str(surface_types)) + def get_surface_type_name(self): return surface_types[self.surface_type] + def set_surface_type(self, name): + if not name in surface_types: + return + self.surface_type = surface_types.index(name) + @staticmethod def read(io_stream): return Triangle( diff --git a/io_mesh_w3d/common/utils/mesh_export.py b/io_mesh_w3d/common/utils/mesh_export.py index d02c3a64..d9f02878 100644 --- a/io_mesh_w3d/common/utils/mesh_export.py +++ b/io_mesh_w3d/common/utils/mesh_export.py @@ -125,6 +125,13 @@ def retrieve_meshes(context, hierarchy, rig, container_name, force_vertex_materi triangle.distance = tri_pos.length mesh_struct.triangles.append(triangle) + face_map_names = [map.name for map in mesh_object.face_maps] + Triangle.validate_face_map_names(context, face_map_names) + + for map in mesh.face_maps: + for i, val in enumerate(map.data): + mesh_struct.triangles[i].set_surface_type(face_map_names[val.value]) + header.face_count = len(mesh_struct.triangles) if mesh_struct.vert_infs: @@ -134,15 +141,15 @@ def retrieve_meshes(context, hierarchy, rig, container_name, force_vertex_materi header.sphCenter = center header.sphRadius = radius - tx_coords = [None] * len(mesh_struct.verts) - for j, face in enumerate(b_mesh.faces): - for loop in face.loops: - vert_index = mesh_struct.triangles[j].vert_ids[loop.index % 3] - tx_coords[vert_index] = mesh.uv_layers[0].data[loop.index].uv.copy() + #tx_coords = [None] * len(mesh_struct.verts) + #for j, face in enumerate(b_mesh.faces): + # for loop in face.loops: + # vert_index = mesh_struct.triangles[j].vert_ids[loop.index % 3] + # tx_coords[vert_index] = mesh.uv_layers[0].data[loop.index].uv.copy() b_mesh.free() - retrieve_material(context, mesh_struct, mesh.materials[0], tx_coords) + #retrieve_material(context, mesh_struct, mesh.materials[0], tx_coords) header.vert_channel_flags = VERTEX_CHANNEL_LOCATION | VERTEX_CHANNEL_NORMAL @@ -152,58 +159,7 @@ def retrieve_meshes(context, hierarchy, rig, container_name, force_vertex_materi mesh_struct.tangents = [] mesh_struct.bitangents = [] - if mesh_struct.prelit_unlit is not None: - # print('prelit unlit') - mesh_struct.header.attrs |= PRELIT_UNLIT - prelit = mesh_struct.prelit_unlit - prelit.mat_info = MaterialInfo( - pass_count=len(prelit.material_passes), - vert_matl_count=len(prelit.vert_materials), - shader_count=len(prelit.shaders), - texture_count=len(prelit.textures)) - - if mesh_struct.prelit_vertex is not None: - # print('prelit vertex') - mesh_struct.header.attrs |= PRELIT_VERTEX - prelit = mesh_struct.prelit_vertex - prelit.mat_info = MaterialInfo( - pass_count=len(prelit.material_passes), - vert_matl_count=len(prelit.vert_materials), - shader_count=len(prelit.shaders), - texture_count=len(prelit.textures)) - - if mesh_struct.prelit_lightmap_multi_pass is not None: - # print('prelit lightmap multi pass') - mesh_struct.header.attrs |= PRELIT_LIGHTMAP_MULTI_PASS - prelit = mesh_struct.prelit_lightmap_multi_pass - prelit.mat_info = MaterialInfo( - pass_count=len(prelit.material_passes), - vert_matl_count=len(prelit.vert_materials), - shader_count=len(prelit.shaders), - texture_count=len(prelit.textures)) - - if mesh_struct.prelit_lightmap_multi_texture is not None: - # print('prelit lightmap multi texture') - mesh_struct.header.attrs |= PRELIT_LIGHTMAP_MULTI_TEXTURE - prelit = mesh_struct.prelit_lightmap_multi_texture - prelit.mat_info = MaterialInfo( - pass_count=len(prelit.material_passes), - vert_matl_count=len(prelit.vert_materials), - shader_count=len(prelit.shaders), - texture_count=len(prelit.textures)) - - - if mesh_struct.prelit_unlit is None and mesh_struct.prelit_vertex is None \ - and mesh_struct.prelit_lightmap_multi_pass is None and mesh_struct.prelit_lightmap_multi_texture is None: - # print('NO PRELIT') - mesh_struct.mat_info = MaterialInfo( - pass_count=len(mesh_struct.material_passes), - vert_matl_count=len(mesh_struct.vert_materials), - shader_count=len(mesh_struct.shaders), - texture_count=len(mesh_struct.textures)) - - mesh_struct.header.matl_count = max( - len(mesh_struct.vert_materials), len(mesh_struct.shader_materials)) + mesh_struct.header.matl_count = max(len(mesh_struct.vert_materials), len(mesh_struct.shader_materials)) mesh_structs.append(mesh_struct) switch_to_pose(rig, 'POSE') From ed1db100a939e12f31c8c0710ce0882e9e63cea9 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Sun, 19 Apr 2020 21:53:39 +0200 Subject: [PATCH 53/62] material import rework wip --- io_mesh_w3d/__init__.py | 15 ------------ io_mesh_w3d/common/shading/node_decision.py | 26 --------------------- io_mesh_w3d/common/utils/material_import.py | 13 +++++++++++ io_mesh_w3d/common/utils/mesh_import.py | 2 +- 4 files changed, 14 insertions(+), 42 deletions(-) delete mode 100644 io_mesh_w3d/common/shading/node_decision.py diff --git a/io_mesh_w3d/__init__.py b/io_mesh_w3d/__init__.py index d2f5fe1a..ae5ece2d 100644 --- a/io_mesh_w3d/__init__.py +++ b/io_mesh_w3d/__init__.py @@ -258,17 +258,6 @@ def draw(self, context): col.prop(context.active_bone, 'visibility') -import nodeitems_utils -from nodeitems_utils import NodeCategory, NodeItem - - -node_categories = [ - NodeCategory('W3D nodes', 'W3D nodes', items=[ - NodeItem('DecisionNode'), - ]) -] - - from io_mesh_w3d.common.shading.node_socket_texture import NodeSocketTexture from io_mesh_w3d.common.shading.node_socket_texture_alpha import NodeSocketTextureAlpha from io_mesh_w3d.common.shading.node_socket_vec2 import NodeSocketVector2 @@ -308,8 +297,6 @@ def register(): for class_ in CLASSES: bpy.utils.register_class(class_) - #nodeitems_utils.register_node_categories('CUSTOM_NODES', node_categories) - bpy.types.TOPBAR_MT_file_import.append(menu_func_import) bpy.types.TOPBAR_MT_file_export.append(menu_func_export) @@ -327,8 +314,6 @@ def unregister(): for class_ in reversed(CLASSES): bpy.utils.unregister_class(class_) - #nodeitems_utils.unregister_node_categories('CUSTOM_NODES') - bpy.types.TOPBAR_MT_file_import.remove(menu_func_import) bpy.types.TOPBAR_MT_file_export.remove(menu_func_export) diff --git a/io_mesh_w3d/common/shading/node_decision.py b/io_mesh_w3d/common/shading/node_decision.py deleted file mode 100644 index e42fdc0b..00000000 --- a/io_mesh_w3d/common/shading/node_decision.py +++ /dev/null @@ -1,26 +0,0 @@ -# -# Written by Stephan Vedder and Michael Schnabel - -import bpy -from bpy.types import Node - - -class DecisionNode(Node): - bl_idname = 'DecisionNode' - bl_label = 'Decision Node' - - def init(self, context): - self.inputs.new('NodeSocketBool', 'decide') - self.inputs.new('NodeSocketFloat', 'value1') - self.inputs.new('NodeSocketFloat', 'value2') - - self.outputs.new('NodeSocketFloat', 'value') - - def copy(self, node): - print('Copying from node ', node) - - def free(self): - print('Removing node ', self, ', Goodbye!') - - def draw_label(self): - return 'Decision' \ No newline at end of file diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index cc23a22e..d0cb7a3f 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -22,6 +22,19 @@ def create_uv_layer(mesh, b_mesh, triangles, tx_coords): uv_layer.data[loop.index].uv = tx_coords[idx].xy +class Pipeline(): + vert_mat_id = None + shader_id = None + texture_id = None + shader_mat_id = None + uv_coords = None + + +def create_materials(context, mesh_struct, mesh, triangles): + + + + def create_material_pass(context, base_struct, mesh, triangles): vert_material = None shader = None diff --git a/io_mesh_w3d/common/utils/mesh_import.py b/io_mesh_w3d/common/utils/mesh_import.py index 73e4bcce..9f7ecf87 100644 --- a/io_mesh_w3d/common/utils/mesh_import.py +++ b/io_mesh_w3d/common/utils/mesh_import.py @@ -35,7 +35,7 @@ def create_mesh(context, mesh_struct, coll): if mesh_struct.is_hidden(): mesh_ob.hide_set(True) - create_material_pass(context, mesh_struct, mesh, triangles) + create_materials(context, mesh_struct, mesh, triangles) def rig_mesh(mesh_struct, hierarchy, rig, sub_object=None): From cb18c3e6fe48118f3d36e2eb74ee7a24ceb5d69f Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Sun, 19 Apr 2020 22:20:32 +0200 Subject: [PATCH 54/62] trying to create the pipelines --- io_mesh_w3d/common/utils/material_import.py | 31 ++++++++++++++++ .../w3d/structs/mesh_structs/material_pass.py | 35 ++++++++++--------- 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index d0cb7a3f..23f4b324 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -30,7 +30,38 @@ class Pipeline(): uv_coords = None +def expand(ids, count): + if len(ids) != count: + return [ids[0]] * count + return ids + + def create_materials(context, mesh_struct, mesh, triangles): + num_faces = len(triangles) + face_pipelines = [[]] * num_faces + + for mat_pass in mesh_struct.material_passes: + vert_mat_ids = [None] * num_faces + shader_ids = [None] * num_faces + texture_ids = [None] * num_faces + shader_mat_ids = [None] * num_faces + uv_coords = None + + if mat_pass.vertex_material_ids: + vert_mat_ids = expand(mat_pass.vertex_material_ids, num_faces) + + if mat_pass.shader_ids: + shader_ids = expand(mat_pass.shader_ids, num_faces) + + if mat_pass.shader_material_ids: + shader_mat_ids = expand(mat_pass.shader_material_ids, num_faces) + + if mat_pass.tx_coords: + uv_coords = mat_pass.tx_coords + + # TODO: do the tx stages stuff + #for tx_stage in mat_pass.tx_stages: + diff --git a/io_mesh_w3d/w3d/structs/mesh_structs/material_pass.py b/io_mesh_w3d/w3d/structs/mesh_structs/material_pass.py index a4f3fd98..8d25f7f2 100644 --- a/io_mesh_w3d/w3d/structs/mesh_structs/material_pass.py +++ b/io_mesh_w3d/w3d/structs/mesh_structs/material_pass.py @@ -24,22 +24,23 @@ def read(context, io_stream, chunk_end): (chunk_type, chunk_size, subchunk_end) = read_chunk_head(io_stream) if chunk_type == W3D_CHUNK_TEXTURE_IDS: - result.tx_ids = read_list(io_stream, subchunk_end, read_long) + result.tx_ids.append(read_list(io_stream, subchunk_end, read_long)) elif chunk_type == W3D_CHUNK_STAGE_TEXCOORDS: - result.tx_coords = read_list( - io_stream, subchunk_end, read_vector2) + result.tx_coords.append(read_list(io_stream, subchunk_end, read_vector2)) elif chunk_type == W3D_CHUNK_PER_FACE_TEXCOORD_IDS: - result.per_face_tx_coords = read_list( - io_stream, subchunk_end, read_vector) + result.per_face_tx_coords.append(read_list(io_stream, subchunk_end, read_vector)) else: skip_unknown_chunk(context, io_stream, chunk_type, chunk_size) return result def size(self, include_head=True): size = const_size(0, include_head) - size += long_list_size(self.tx_ids) - size += vec2_list_size(self.tx_coords) - size += vec_list_size(self.per_face_tx_coords) + for tx_ids in self.tx_ids: + size += long_list_size(tx_ids) + for tx_coords in self.tx_coords: + size += vec2_list_size(tx_coords) + for per_face_tx_coords in self.per_face_tx_coords: + size += vec_list_size(self.per_face_tx_coords) return size def write(self, io_stream): @@ -47,19 +48,19 @@ def write(self, io_stream): self.size(False), has_sub_chunks=True) if self.tx_ids: - write_chunk_head(W3D_CHUNK_TEXTURE_IDS, io_stream, - long_list_size(self.tx_ids, False)) - write_list(self.tx_ids, io_stream, write_long) + for tx_ids in self.tx_ids: + write_chunk_head(W3D_CHUNK_TEXTURE_IDS, io_stream, long_list_size(tx_ids, False)) + write_list(tx_ids, io_stream, write_long) if self.tx_coords: - write_chunk_head(W3D_CHUNK_STAGE_TEXCOORDS, io_stream, - vec2_list_size(self.tx_coords, False)) - write_list(self.tx_coords, io_stream, write_vector2) + for tx_coords in self.tx_coords: + write_chunk_head(W3D_CHUNK_STAGE_TEXCOORDS, io_stream, vec2_list_size(tx_coords, False)) + write_list(tx_coords, io_stream, write_vector2) if self.per_face_tx_coords: - write_chunk_head(W3D_CHUNK_PER_FACE_TEXCOORD_IDS, io_stream, - vec_list_size(self.per_face_tx_coords, False)) - write_list(self.per_face_tx_coords, io_stream, write_vector) + for per_face_tx_coords in self.per_face_tx_coords: + write_chunk_head(W3D_CHUNK_PER_FACE_TEXCOORD_IDS, io_stream, vec_list_size(per_face_tx_coords, False)) + write_list(per_face_tx_coords, io_stream, write_vector) W3D_CHUNK_MATERIAL_PASS = 0x00000038 From fe12c7993b6e7d3176dd8606e13714129e015411 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Mon, 20 Apr 2020 01:59:52 +0200 Subject: [PATCH 55/62] lots of improvements on pipeline import and creation --- io_mesh_w3d/__init__.py | 4 - io_mesh_w3d/common/utils/material_import.py | 211 +++++++++++------- io_mesh_w3d/node_group_templates/BasicW3D.xml | 2 +- io_mesh_w3d/node_group_templates/Infantry.xml | 2 +- .../node_group_templates/NormalMapped.xml | 2 +- 5 files changed, 136 insertions(+), 85 deletions(-) diff --git a/io_mesh_w3d/__init__.py b/io_mesh_w3d/__init__.py index ae5ece2d..f1eb2a5b 100644 --- a/io_mesh_w3d/__init__.py +++ b/io_mesh_w3d/__init__.py @@ -263,7 +263,6 @@ def draw(self, context): from io_mesh_w3d.common.shading.node_socket_vec2 import NodeSocketVector2 from io_mesh_w3d.common.shading.node_socket_vec4 import NodeSocketVector4 from io_mesh_w3d.common.shading.node_socket_enum import NodeSocketMaterialAttributes -from io_mesh_w3d.common.shading.node_decision import DecisionNode CLASSES = ( @@ -272,7 +271,6 @@ def draw(self, context): NodeSocketVector2, NodeSocketVector4, NodeSocketMaterialAttributes, - DecisionNode, ExportW3D, ImportW3D, MESH_PROPERTIES_PANEL_PT_w3d, @@ -309,8 +307,6 @@ def register(): def unregister(): - nodeitems_utils.unregister_node_categories('CUSTOM_NODES') - for class_ in reversed(CLASSES): bpy.utils.unregister_class(class_) diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index 23f4b324..f324467c 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -11,23 +11,63 @@ from io_mesh_w3d.common.structs.mesh_structs.shader_material import * -def create_uv_layer(mesh, b_mesh, triangles, tx_coords): +def get_or_create_uv_layer(mesh, b_mesh, triangles, tx_coords): if tx_coords is None: return + for uv_layer in mesh.uv_layers: + uv_layer_exists = True + for i, face in enumerate(b_mesh.faces): + for loop in face.loops: + idx = triangles[i][loop.index % 3] + if uv_layer.data[loop.index].uv != tx_coords[idx].xy: + uv_layer_exists = False + if uv_layer_exists: + return uv_layer.name + uv_layer = mesh.uv_layers.new(do_init=False) for i, face in enumerate(b_mesh.faces): for loop in face.loops: idx = triangles[i][loop.index % 3] uv_layer.data[loop.index].uv = tx_coords[idx].xy + return uv_layer.name + +class PipelineSet(): + def __init__(self): + self.pipelines = [] + + def add(self, set): + self.pipelines.append(set) + + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + else: + return False + + def __ne__(self, other): + return not self.__eq__(other) + class Pipeline(): - vert_mat_id = None - shader_id = None - texture_id = None - shader_mat_id = None - uv_coords = None + def __init__(self, type='', pass_index=0, vert_mat=None, shader=None, texture=None, shader_mat=None, uv_map=None): + self.type = type + self.pass_index = pass_index + self.vert_mat = vert_mat + self.shader = shader + self.texture = texture + self.shader_mat = shader_mat + self.uv_map = uv_map + + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + else: + return False + + def __ne__(self, other): + return not self.__eq__(other) def expand(ids, count): @@ -37,15 +77,18 @@ def expand(ids, count): def create_materials(context, mesh_struct, mesh, triangles): + b_mesh = bmesh.new() + b_mesh.from_mesh(mesh) + num_faces = len(triangles) - face_pipelines = [[]] * num_faces + face_pipeline_sets = [None] * num_faces - for mat_pass in mesh_struct.material_passes: + for i, mat_pass in enumerate(mesh_struct.material_passes): vert_mat_ids = [None] * num_faces shader_ids = [None] * num_faces - texture_ids = [None] * num_faces + texture_ids = [] + uv_maps = [] shader_mat_ids = [None] * num_faces - uv_coords = None if mat_pass.vertex_material_ids: vert_mat_ids = expand(mat_pass.vertex_material_ids, num_faces) @@ -57,76 +100,92 @@ def create_materials(context, mesh_struct, mesh, triangles): shader_mat_ids = expand(mat_pass.shader_material_ids, num_faces) if mat_pass.tx_coords: - uv_coords = mat_pass.tx_coords - - # TODO: do the tx stages stuff - #for tx_stage in mat_pass.tx_stages: - - - - - -def create_material_pass(context, base_struct, mesh, triangles): - vert_material = None - shader = None - texture = None - tx_coords = None - - b_mesh = bmesh.new() - b_mesh.from_mesh(mesh) - mat_pass = base_struct.material_passes[0] - - if mat_pass.vertex_material_ids: - vert_material = base_struct.vert_materials[mat_pass.vertex_material_ids[0]] - - if mat_pass.shader_ids: - shader = base_struct.shaders[mat_pass.shader_ids[0]] - - if mat_pass.tx_stages: - tx_stage = mat_pass.tx_stages[0] - texture = base_struct.textures[tx_stage.tx_ids[0]] - tx_coords = tx_stage.tx_coords + uv_maps = get_or_create_uv_layer(mesh, b_mesh, triangles, mat_pass.tx_coords) + + for tx_stage in mat_pass.tx_stages: + for tx_coords in tx_stage.tx_coords: + uv_maps.append(get_or_create_uv_layer(mesh, b_mesh, triangles, tx_coords)) + + for k, tx_ids in enumerate(tx_stage.tx_ids): + tex_ids = expand(tx_ids, num_faces) + uv_map = uv_maps[k] + for j, tri in enumerate(triangles): + pipeline = Pipeline(type='vertex', pass_index=i) + pipeline.vert_mat = mesh_struct.vert_materials[vert_mat_ids[j]] + pipeline.shader = mesh_struct.shaders[shader_ids[j]] + pipeline.texture = mesh_struct.textures[tex_ids[j]] + pipeline.uv_map = uv_map + + if face_pipeline_sets[j] is None: + face_pipeline_sets[j] = PipelineSet() + face_pipeline_sets[j].add(pipeline) + + if not mat_pass.tx_stages: + for j, tri in enumerate(triangles): + pipeline = Pipeline( + type='shader', + pass_index=i, + shader_mat=mesh_struct.shader_materials[shader_mat_ids[j]], + uv_map=uv_maps) + + if face_pipeline_sets[j] is None: + face_pipeline_sets[j] = PipelineSet() + face_pipeline_sets[j].add(pipeline) + + unique_pipeline_sets = [] + face_mat_indices = [0] * num_faces + + for i, pipeline_set in enumerate(face_pipeline_sets): + if pipeline_set in unique_pipeline_sets: + face_mat_indices[i] = unique_pipeline_sets.index(pipeline_set) + else: + unique_pipeline_sets.append(pipeline_set) - if vert_material is not None and shader is not None: - create_vertex_material(context, mesh, b_mesh, triangles, vert_material, shader, texture, tx_coords) + for pps in unique_pipeline_sets: + create_material(context, mesh, b_mesh, triangles, pps) - if mat_pass.shader_material_ids: - shader_material = base_struct.shader_materials[0] - create_shader_material(context, mesh, b_mesh, triangles, shader_material, mat_pass.tx_coords) + for i, polygon in enumerate(mesh.polygons): + polygon.material_index = face_mat_indices[i] b_mesh.free() -########################################################################## -# vertex material -########################################################################## - -def create_vertex_material(context, mesh, b_mesh, triangles, vert_mat, shader, texture_struct, tx_coords): - material = bpy.data.materials.new(mesh.name + '.' + vert_mat.vm_name) +def create_material(context, mesh, b_mesh, triangles, pps): + material = bpy.data.materials.new(mesh.name) mesh.materials.append(material) - create_uv_layer(mesh, b_mesh, triangles, tx_coords) - material.use_nodes = True material.shadow_method = 'CLIP' material.blend_method = 'BLEND' material.show_transparent_back = False node_tree = material.node_tree - links = node_tree.links - node_tree.nodes.remove(node_tree.nodes.get('Principled BSDF')) - instance = VertexMaterialGroup.create(node_tree, vert_mat, shader) - instance.label = vert_mat.vm_name + for pipeline in pps.pipelines: + if pipeline.type == 'vertex': + create_vertex_material_pipeline(context, node_tree, pipeline) + else: + create_shader_material_pipeline(context, node_tree, pipeline) + + +########################################################################## +# vertex material +########################################################################## + +def create_vertex_material_pipeline(context, node_tree, pipeline): + instance = VertexMaterialGroup.create(node_tree, pipeline.vert_mat, pipeline.shader) + instance.label = pipeline.vert_mat.vm_name instance.location = (0, 300) instance.width = 200 output = node_tree.nodes.get('Material Output') + + links = node_tree.links links.new(instance.outputs['BSDF'], output.inputs['Surface']) - if texture_struct is not None: - texture = find_texture(context, texture_struct.file, texture_struct.id) + if pipeline.texture is not None: + texture = find_texture(context, pipeline.texture.file, pipeline.texture.id) texture_node = node_tree.nodes.new('ShaderNodeTexImage') texture_node.image = texture @@ -134,28 +193,19 @@ def create_vertex_material(context, mesh, b_mesh, triangles, vert_mat, shader, t links.new(texture_node.outputs['Color'], instance.inputs['DiffuseTexture']) links.new(texture_node.outputs['Alpha'], instance.inputs['DiffuseTextureAlpha']) + uv_node = node_tree.nodes.new('ShaderNodeUVMap') + uv_node.location = (-550, 300) + uv_node.uv_map = pipeline.uv_map + links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) + ########################################################################## # shader material ########################################################################## -def create_shader_material(context, mesh, b_mesh, triangles, shader_mat, tx_coords): - mat_name = shader_mat.header.type_name - create_uv_layer(mesh, b_mesh, triangles, tx_coords) - - if mat_name in bpy.data.materials: - mesh.materials.append(bpy.data.materials[mat_name]) - return - - material = bpy.data.materials.new(mat_name) - mesh.materials.append(material) - material.use_nodes = True - material.blend_method = 'BLEND' - material.show_transparent_back = False - - node_tree = material.node_tree - node_tree.nodes.remove(node_tree.nodes.get('Principled BSDF')) +def create_shader_material_pipeline(context, node_tree, pipeline): + mat_name = pipeline.shader_mat.header.type_name instance = node_tree.nodes.new(type='ShaderNodeGroup') instance.node_tree = bpy.data.node_groups[mat_name] @@ -165,21 +215,26 @@ def create_shader_material(context, mesh, b_mesh, triangles, shader_mat, tx_coor links = node_tree.links - if shader_mat.header.technique is not None: - instance.inputs['Technique'].default_value = shader_mat.header.technique + if pipeline.shader_mat.header.technique is not None: + instance.inputs['Technique'].default_value = pipeline.shader_mat.header.technique y = 300 - for prop in shader_mat.properties: + for prop in pipeline.shader_mat.properties: if prop.type == STRING_PROPERTY and prop.value != '': texture_node = node_tree.nodes.new('ShaderNodeTexImage') texture_node.image = find_texture(context, prop.value) texture_node.location = (-350, y) - y -= 300 links.new(texture_node.outputs['Color'], instance.inputs[prop.name]) index = instance.inputs.keys().index(prop.name) links.new(texture_node.outputs['Alpha'], instance.inputs[index + 1]) + uv_node = node_tree.nodes.new('ShaderNodeUVMap') + uv_node.location = (-550, y) + uv_node.uv_map = pipeline.uv_map + links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) + y -= 300 + elif prop.type == VEC4_PROPERTY: instance.inputs[prop.name].default_value = prop.to_rgba() else: diff --git a/io_mesh_w3d/node_group_templates/BasicW3D.xml b/io_mesh_w3d/node_group_templates/BasicW3D.xml index 71f0f598..ef4704d8 100644 --- a/io_mesh_w3d/node_group_templates/BasicW3D.xml +++ b/io_mesh_w3d/node_group_templates/BasicW3D.xml @@ -6,7 +6,7 @@ - + diff --git a/io_mesh_w3d/node_group_templates/Infantry.xml b/io_mesh_w3d/node_group_templates/Infantry.xml index 2e93699f..879dd077 100644 --- a/io_mesh_w3d/node_group_templates/Infantry.xml +++ b/io_mesh_w3d/node_group_templates/Infantry.xml @@ -6,7 +6,7 @@ - + diff --git a/io_mesh_w3d/node_group_templates/NormalMapped.xml b/io_mesh_w3d/node_group_templates/NormalMapped.xml index 31bc24ce..c12505f6 100644 --- a/io_mesh_w3d/node_group_templates/NormalMapped.xml +++ b/io_mesh_w3d/node_group_templates/NormalMapped.xml @@ -6,7 +6,7 @@ - LON + From b0d05a9c1f6998a6f04e6c5537602e1907fd211d Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Mon, 20 Apr 2020 21:42:17 +0200 Subject: [PATCH 56/62] added custom sockets for shader enums --- io_mesh_w3d/__init__.py | 15 +- .../common/shading/node_socket_enum.py | 164 +++++++++++++++++- .../common/shading/vertex_material_group.py | 45 ++--- 3 files changed, 197 insertions(+), 27 deletions(-) diff --git a/io_mesh_w3d/__init__.py b/io_mesh_w3d/__init__.py index f1eb2a5b..d1c32426 100644 --- a/io_mesh_w3d/__init__.py +++ b/io_mesh_w3d/__init__.py @@ -262,15 +262,26 @@ def draw(self, context): from io_mesh_w3d.common.shading.node_socket_texture_alpha import NodeSocketTextureAlpha from io_mesh_w3d.common.shading.node_socket_vec2 import NodeSocketVector2 from io_mesh_w3d.common.shading.node_socket_vec4 import NodeSocketVector4 -from io_mesh_w3d.common.shading.node_socket_enum import NodeSocketMaterialAttributes +#from io_mesh_w3d.common.shading.node_socket_enum import * CLASSES = ( + #NodeSocketEnum, + #NodeSocketEnumMaterialAttributes, + #NodeSocketEnumDepthCompare, + #NodeSocketEnumDepthmaskWrite, + #NodeSocketEnumAlphatest, + #NodeSocketEnumDestBlendFunc, + #NodeSocketEnumPriGradient, + #NodeSocketEnumSecGradient, + #NodeSocketEnumSrcBlendFunc, + #NodeSocketEnumTexturing, + #NodeSocketEnumDetailColorFunc, + #NodeSocketEnumDetailAlphaFunc, NodeSocketTexture, NodeSocketTextureAlpha, NodeSocketVector2, NodeSocketVector4, - NodeSocketMaterialAttributes, ExportW3D, ImportW3D, MESH_PROPERTIES_PANEL_PT_w3d, diff --git a/io_mesh_w3d/common/shading/node_socket_enum.py b/io_mesh_w3d/common/shading/node_socket_enum.py index c569c510..c8d71b96 100644 --- a/io_mesh_w3d/common/shading/node_socket_enum.py +++ b/io_mesh_w3d/common/shading/node_socket_enum.py @@ -2,10 +2,10 @@ # Written by Stephan Vedder and Michael Schnabel import bpy -from bpy.types import NodeSocketInt +from bpy.types import NodeSocket -class NodeSocketEnum(NodeSocketInt): +class NodeSocketEnum(NodeSocket): bl_idname = 'NodeSocketEnum' bl_label = 'Enum Node Socket' @@ -28,7 +28,8 @@ def draw(self, context, layout, node, text): def draw_color(self, context, node): return (1.0, 0.4, 0.216, 0.5) -class NodeSocketMaterialAttributes(NodeSocketEnum): + +class NodeSocketEnumMaterialAttributes(NodeSocketEnum): bl_idname = 'NodeSocketMaterialAttributes' bl_label = 'Material Attributes Enum Flag Node Socket' @@ -42,4 +43,159 @@ class NodeSocketMaterialAttributes(NodeSocketEnum): ('COPY_SPECULAR_TO_DIFFUSE', 'CopySpecularToDiffuse', 'desc: todo', 4), ('DEPTH_CUE_TO_ALPHA', 'DepthCueToAlpha', 'desc: todo', 8)], default=set(), - options={'ENUM_FLAG'}) \ No newline at end of file + options={'ENUM_FLAG'}) + + +class NodeSocketEnumDepthCompare(NodeSocketEnum): + bl_idname = 'NodeSocketEnumDepthCompare' + bl_label = 'Depth Compare Enum Node Socket' + + default_value: bpy.props.EnumProperty( + name='DepthCompare', + description='todo', + items=[ + ('0', 'PASS_NEVER', 'pass never (i.e. always fail depth comparison test)'), + ('1', 'PASS_LESS', 'pass if incoming less than stored'), + ('2', 'PASS_EQUAL', 'pass if incoming equal to stored'), + ('3', 'PASS_LEQUAL', 'pass if incoming less than or equal to stored (default)'), + ('4', 'PASS_GREATER', 'pass if incoming greater than stored'), + ('5', 'PASS_NOTEQUAL', 'pass if incoming not equal to stored'), + ('6', 'PASS_GEQUAL', 'pass if incoming greater than or equal to stored'), + ('7', 'PASS_ALWAYS', 'pass always')], + default='3') + + +class NodeSocketEnumDepthmaskWrite(NodeSocketEnum): + bl_idname = 'NodeSocketEnumDepthmaskWrite' + bl_label = 'Depthmask Write Enum Node Socket' + + default_value: bpy.props.EnumProperty( + name='DepthmaskWrite', + description='todo', + items=[ + ('0', 'DISABLE', 'disable depth buffer writes'), + ('1', 'ENABLE', 'enable depth buffer writes (default)')], + default='1') + + +class NodeSocketEnumAlphatest(NodeSocketEnum): + bl_idname = 'NodeSocketEnumAlphaTest' + bl_label = 'Alphatest Enum Node Socket' + + default_value: bpy.props.EnumProperty( + name='Alphatest', + description='todo', + items=[ + ('0', 'DISABLE', 'disable alpha testing (default)'), + ('1', 'ENABLE', 'enable alpha testing')], + default='0') + + +class NodeSocketEnumDestBlendFunc(NodeSocketEnum): + bl_idname = 'NodeSocketEnumDestBlendFunc' + bl_label = 'DestBlendFunc Enum Node Socket' + + default_value: bpy.props.EnumProperty( + name='DestBlendFunc', + description='todo', + items=[ + ('0', 'ZERO', 'destination pixel does not affect blending (default)'), + ('1', 'ONE', 'destination pixel added unmodified'), + ('2', 'SRC_COLOR', 'destination pixel multiplied by fragment RGB components'), + ('3', 'ONE_MINUS_SRC_COLOR', 'destination pixel multiplied by one minus (i.e. inverse) fragment RGB components'), + ('4', 'SRC_ALPHA', 'destination pixel multiplied by fragment alpha component'), + ('5', 'ONE_MINUS_SRC_ALPHA', 'destination pixel multiplied by fragment inverse alpha'), + ('6', 'SRC_COLOR_PREFOG', 'destination pixel multiplied by fragment RGB components prior to fogging')], + default='0') + + +class NodeSocketEnumPriGradient(NodeSocketEnum): + bl_idname = 'NodeSocketEnumPriGradient' + bl_label = 'PriGradient Enum Node Socket' + + default_value: bpy.props.EnumProperty( + name='PriGradient', + description='todo', + items=[ + ('0', 'DISABLE', 'disable primary gradient (same as OpenGL ´decal´ texture blend)'), + ('1', 'MODULATE', 'modulate fragment ARGB by gradient ARGB (default)'), + ('2', 'ADD', 'add gradient RGB to fragment RGB, copy gradient A to fragment A'), + ('3', 'BUMPENVMAP', 'environment-mapped bump mapping')], + default='1') + + +class NodeSocketEnumSecGradient(NodeSocketEnum): + bl_idname = 'NodeSocketEnumSecGradient' + bl_label = 'SecGradient Enum Node Socket' + + default_value: bpy.props.EnumProperty( + name='SecGradient', + description='todo', + items=[ + ('0', 'DISABLE', 'do not draw secondary gradient (default)'), + ('1', 'ENABLE', 'add secondary gradient RGB to fragment RGB')], + default='0') + + + +class NodeSocketEnumSrcBlendFunc(NodeSocketEnum): + bl_idname = 'NodeSocketEnumSrcBlendFunc' + bl_label = 'SrcBlendFunc Enum Node Socket' + + default_value: bpy.props.EnumProperty( + name='SrcBlendFunc', + description='todo', + items=[ + ('0', 'ZERO', 'fragment not added to color buffer'), + ('1', 'ONE', 'fragment added unmodified to color buffer (default)'), + ('2', 'SRC_ALPHA', 'fragment RGB components multiplied by fragment A'), + ('3', 'ONE_MINUS_SRC_ALPHA', 'fragment RGB components multiplied by fragment inverse (one minus) A')], + default='1') + + +class NodeSocketEnumTexturing(NodeSocketEnum): + bl_idname = 'NodeSocketEnumTexturing' + bl_label = 'Texturing Enum Node Socket' + + default_value: bpy.props.EnumProperty( + name='Texturing', + description='todo', + items=[ + ('0', 'DISABLE', 'no texturing (treat fragment initial color as 1,1,1,1) (default)'), + ('1', 'ENABLE', 'enable texturing')], + default='0') + + +class NodeSocketEnumDetailColorFunc(NodeSocketEnum): + bl_idname = 'NodeSocketEnumDetailColorFunc' + bl_label = 'DetailColorFunc Enum Node Socket' + + default_value: bpy.props.EnumProperty( + name='DetailColorFunc', + description='todo', + items=[ + ('0', 'DISABLE', 'local (default)'), + ('1', 'DETAIL', 'other'), + ('2', 'SCALE', 'local * other'), + ('3', 'INVSCALE', '~(~local * ~other) = local + (1-local)*other'), + ('4', 'ADD', 'local + other'), + ('5', 'SUB', 'local - other'), + ('6', 'SUBR', 'other - local'), + ('7', 'BLEND', '(localAlpha)*local + (~localAlpha)*other'), + ('8', 'DETAILBLEND', '(otherAlpha)*local + (~otherAlpha)*other')], + default='0') + + +class NodeSocketEnumDetailAlphaFunc(NodeSocketEnum): + bl_idname = 'NodeSocketEnumDetailAlphaFunc' + bl_label = 'DetailAlphaFunc Enum Node Socket' + + default_value: bpy.props.EnumProperty( + name='DetailAlphaFunc', + description='todo', + items=[ + ('0', 'DISABLE', 'local (default)'), + ('1', 'DETAIL', 'other'), + ('2', 'SCALE', 'local * other'), + ('3', 'INVSCALE', '~(~local * ~other) = local + (1-local)*other')], + default='0') \ No newline at end of file diff --git a/io_mesh_w3d/common/shading/vertex_material_group.py b/io_mesh_w3d/common/shading/vertex_material_group.py index 960e5ac8..5c3e811d 100644 --- a/io_mesh_w3d/common/shading/vertex_material_group.py +++ b/io_mesh_w3d/common/shading/vertex_material_group.py @@ -27,7 +27,7 @@ def create(node_tree, vert_mat, shader): if vert_mat.vm_info.attributes & DEPTH_CUE_TO_ALPHA: attributes.add('DEPTH_CUE_TO_ALPHA') - instance.inputs['Attributes'].default_value = attributes + #instance.inputs['Attributes'].default_value = attributes # TODO: translate those to shader properties # floats: UPerSec, VPerSec, UScale, VScale, FPS, Speed, UCenter, VCenter, UAmp, UFreq, UPhase, VAmp, VFreq, VPhase, @@ -46,14 +46,17 @@ def create(node_tree, vert_mat, shader): instance.inputs['Opacity'].default_value = vert_mat.vm_info.shininess instance.inputs['Translucency'].default_value = vert_mat.vm_info.shininess + return instance + instance.inputs['DepthCompare'].default_value = shader.depth_compare - instance.inputs['DepthMask'].default_value = shader.depth_mask + instance.inputs['DepthMaskWrite'].default_value = shader.depth_mask instance.inputs['ColorMask'].default_value = shader.color_mask - instance.inputs['DestBlend'].default_value = shader.dest_blend instance.inputs['FogFunc'].default_value = shader.fog_func + instance.inputs['DestBlendFunc'].default_value = shader.dest_blend instance.inputs['PriGradient'].default_value = shader.pri_gradient instance.inputs['SecGradient'].default_value = shader.sec_gradient - instance.inputs['SrcBlend'].default_value = shader.src_blend + instance.inputs['SrcBlendFunc'].default_value = shader.src_blend + instance.inputs['Texturing'].default_value = shader.texturing instance.inputs['DetailColorFunc'].default_value = shader.detail_color_func instance.inputs['DetailAlphaFunc'].default_value = shader.detail_alpha_func instance.inputs['Preset'].default_value = shader.shader_preset @@ -81,14 +84,13 @@ def register(name): group_inputs = group.nodes.new('NodeGroupInput') group_inputs.location = (-350,0) - group.inputs.new('NodeSocketMaterialAttributes', 'Attributes') + # group.inputs.new('NodeSocketEnumMaterialAttributes', 'Attributes') group.inputs.new('NodeSocketString', 'VM_ARGS_0') group.inputs.new('NodeSocketString', 'VM_ARGS_1') group.inputs.new('NodeSocketColor', 'Diffuse') group.inputs['Diffuse'].default_value = (0.8, 0.8, 0.8, 1.0) group.inputs.new('NodeSocketTexture', 'DiffuseTexture') group.inputs.new('NodeSocketTextureAlpha', 'DiffuseTextureAlpha') - VertexMaterialGroup.addInputInt(group, 'DestBlend', max=1) group.inputs.new('NodeSocketColor', 'Ambient') group.inputs['Ambient'].default_value = (0.8, 0.8, 0.8, 1.0) group.inputs.new('NodeSocketColor', 'Specular') @@ -99,20 +101,21 @@ def register(name): group.inputs.new('NodeSocketFloat', 'Opacity') group.inputs.new('NodeSocketFloat', 'Translucency') - VertexMaterialGroup.addInputInt(group, 'DepthCompare') - VertexMaterialGroup.addInputInt(group, 'DepthMask') - VertexMaterialGroup.addInputInt(group, 'ColorMask') - VertexMaterialGroup.addInputInt(group, 'FogFunc') - VertexMaterialGroup.addInputInt(group, 'PriGradient') - VertexMaterialGroup.addInputInt(group, 'SecGradient') - VertexMaterialGroup.addInputInt(group, 'SrcBlend') - VertexMaterialGroup.addInputInt(group, 'Texturing') - VertexMaterialGroup.addInputInt(group, 'DetailColorFunc') - VertexMaterialGroup.addInputInt(group, 'DetailAlphaFunc') - VertexMaterialGroup.addInputInt(group, 'Preset') - VertexMaterialGroup.addInputInt(group, 'AlphaTest') - VertexMaterialGroup.addInputInt(group, 'PostDetailColorFunc') - VertexMaterialGroup.addInputInt(group, 'PostDetailAlphaFunc') + #group.inputs.new('NodeSocketEnumDepthCompare', 'DepthCompare') + #group.inputs.new('NodeSocketEnumDepthMaskWrite', 'DepthMaskWrite') + VertexMaterialGroup.addInputInt(group, 'ColorMask') # obsolete (w3d_file.h) + VertexMaterialGroup.addInputInt(group, 'FogFunc') # obsolete (w3d_file.h) + #group.inputs.new('NodeSocketEnumDestBlendFunc', 'DestBlendFunc') + #group.inputs.new('NodeSocketEnumPriGradient', 'PriGradient') + #group.inputs.new('NodeSocketEnumSecGradient', 'SecGradient') + #group.inputs.new('NodeSocketEnumSrcBlendFunc', 'SrcBlendFunc') + #group.inputs.new('NodeSocketEnumTexturing', 'Texturing') + #group.inputs.new('NodeSocketEnumDetailColorFunc', 'DetailColorFunc') + #group.inputs.new('NodeSocketEnumDetailAlphaFunc', 'DetailAlphaFunc') + VertexMaterialGroup.addInputInt(group, 'Preset') # obsolete (w3d_file.h) + #group.inputs.new('NodeSocketEnumAlphaTest', 'AlphaTest') + #group.inputs.new('NodeSocketEnumDetailColorFunc', 'PostDetailColorFunc') + #group.inputs.new('NodeSocketEnumDetailAlphaFunc', 'PostDetailAlphaFunc') # create group outputs group_outputs = group.nodes.new('NodeGroupOutput') @@ -125,7 +128,7 @@ def register(name): alpha_pipeline.node_tree = bpy.data.node_groups['AlphaPipeline'] links.new(group_inputs.outputs['DiffuseTexture'], alpha_pipeline.inputs['Diffuse']) links.new(group_inputs.outputs['DiffuseTextureAlpha'], alpha_pipeline.inputs['Alpha']) - links.new(group_inputs.outputs['DestBlend'], alpha_pipeline.inputs['DestBlend']) + #links.new(group_inputs.outputs['AlphaTest'], alpha_pipeline.inputs['DestBlend']) shader = node_tree.nodes.new('ShaderNodeEeveeSpecular') shader.label = 'Shader' From 5d192cc7ab4fa8a2fa3b477d3d15111f97936f0b Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Thu, 23 Apr 2020 23:48:19 +0200 Subject: [PATCH 57/62] work on unique pipeline import, prelit stuff --- io_mesh_w3d/__init__.py | 46 ++++--- .../common/shading/vertex_material_group.py | 61 +++++----- .../structs/mesh_structs/shader_material.py | 9 ++ .../common/structs/mesh_structs/texture.py | 18 +++ io_mesh_w3d/common/utils/material_import.py | 114 ++++++++++-------- io_mesh_w3d/common/utils/mesh_import.py | 4 +- .../common/utils/node_group_creator.py | 11 ++ .../w3d/structs/mesh_structs/shader.py | 6 + .../structs/mesh_structs/vertex_material.py | 18 +++ 9 files changed, 194 insertions(+), 93 deletions(-) diff --git a/io_mesh_w3d/__init__.py b/io_mesh_w3d/__init__.py index d1c32426..90664a98 100644 --- a/io_mesh_w3d/__init__.py +++ b/io_mesh_w3d/__init__.py @@ -262,22 +262,22 @@ def draw(self, context): from io_mesh_w3d.common.shading.node_socket_texture_alpha import NodeSocketTextureAlpha from io_mesh_w3d.common.shading.node_socket_vec2 import NodeSocketVector2 from io_mesh_w3d.common.shading.node_socket_vec4 import NodeSocketVector4 -#from io_mesh_w3d.common.shading.node_socket_enum import * +from io_mesh_w3d.common.shading.node_socket_enum import * CLASSES = ( - #NodeSocketEnum, - #NodeSocketEnumMaterialAttributes, - #NodeSocketEnumDepthCompare, - #NodeSocketEnumDepthmaskWrite, - #NodeSocketEnumAlphatest, - #NodeSocketEnumDestBlendFunc, - #NodeSocketEnumPriGradient, - #NodeSocketEnumSecGradient, - #NodeSocketEnumSrcBlendFunc, - #NodeSocketEnumTexturing, - #NodeSocketEnumDetailColorFunc, - #NodeSocketEnumDetailAlphaFunc, + NodeSocketEnum, + NodeSocketEnumMaterialAttributes, + NodeSocketEnumDepthCompare, + NodeSocketEnumDepthmaskWrite, + NodeSocketEnumAlphatest, + NodeSocketEnumDestBlendFunc, + NodeSocketEnumPriGradient, + NodeSocketEnumSecGradient, + NodeSocketEnumSrcBlendFunc, + NodeSocketEnumTexturing, + NodeSocketEnumDetailColorFunc, + NodeSocketEnumDetailAlphaFunc, NodeSocketTexture, NodeSocketTextureAlpha, NodeSocketVector2, @@ -288,8 +288,10 @@ def draw(self, context): BONE_PROPERTIES_PANEL_PT_w3d) +from io_mesh_w3d.common.utils.node_group_creator import NodeGroupCreator +from io_mesh_w3d.common.shading.vertex_material_group import VertexMaterialGroup + def register_node_groups(): - from io_mesh_w3d.common.utils.node_group_creator import NodeGroupCreator dirname = os.path.dirname(__file__) directory = os.path.join(dirname, 'node_group_templates') @@ -298,7 +300,6 @@ def register_node_groups(): continue NodeGroupCreator().create(directory, file) - from io_mesh_w3d.common.shading.vertex_material_group import VertexMaterialGroup VertexMaterialGroup.register(VertexMaterialGroup.name) @@ -317,6 +318,18 @@ def register(): Timer(1, register_node_groups, ()).start() +def unregister_node_groups(): + dirname = os.path.dirname(__file__) + directory = os.path.join(dirname, 'node_group_templates') + + for file in os.listdir(directory): + if not file.endswith(".xml"): + continue + NodeGroupCreator().unregister(directory, file) + + VertexMaterialGroup.unregister(VertexMaterialGroup.name) + + def unregister(): for class_ in reversed(CLASSES): bpy.utils.unregister_class(class_) @@ -324,7 +337,8 @@ def unregister(): bpy.types.TOPBAR_MT_file_import.remove(menu_func_import) bpy.types.TOPBAR_MT_file_export.remove(menu_func_export) + unregister_node_groups() + if __name__ == '__main__': register() - register_node_groups() diff --git a/io_mesh_w3d/common/shading/vertex_material_group.py b/io_mesh_w3d/common/shading/vertex_material_group.py index 5c3e811d..5553ddfd 100644 --- a/io_mesh_w3d/common/shading/vertex_material_group.py +++ b/io_mesh_w3d/common/shading/vertex_material_group.py @@ -17,6 +17,7 @@ def create(node_tree, vert_mat, shader): instance.node_tree = bpy.data.node_groups['VertexMaterial'] instance.label = vert_mat.vm_name + # TODO: this should be done in parsing of vm_info attributes = {'DEFAULT'} if vert_mat.vm_info.attributes & USE_DEPTH_CUE: attributes.add('USE_DEPTH_CUE') @@ -27,7 +28,7 @@ def create(node_tree, vert_mat, shader): if vert_mat.vm_info.attributes & DEPTH_CUE_TO_ALPHA: attributes.add('DEPTH_CUE_TO_ALPHA') - #instance.inputs['Attributes'].default_value = attributes + instance.inputs['Attributes'].default_value = attributes # TODO: translate those to shader properties # floats: UPerSec, VPerSec, UScale, VScale, FPS, Speed, UCenter, VCenter, UAmp, UFreq, UPhase, VAmp, VFreq, VPhase, @@ -46,23 +47,21 @@ def create(node_tree, vert_mat, shader): instance.inputs['Opacity'].default_value = vert_mat.vm_info.shininess instance.inputs['Translucency'].default_value = vert_mat.vm_info.shininess - return instance - - instance.inputs['DepthCompare'].default_value = shader.depth_compare - instance.inputs['DepthMaskWrite'].default_value = shader.depth_mask + instance.inputs['DepthCompare'].default_value = str(shader.depth_compare) + instance.inputs['DepthMaskWrite'].default_value = str(shader.depth_mask) instance.inputs['ColorMask'].default_value = shader.color_mask instance.inputs['FogFunc'].default_value = shader.fog_func - instance.inputs['DestBlendFunc'].default_value = shader.dest_blend - instance.inputs['PriGradient'].default_value = shader.pri_gradient - instance.inputs['SecGradient'].default_value = shader.sec_gradient - instance.inputs['SrcBlendFunc'].default_value = shader.src_blend - instance.inputs['Texturing'].default_value = shader.texturing - instance.inputs['DetailColorFunc'].default_value = shader.detail_color_func - instance.inputs['DetailAlphaFunc'].default_value = shader.detail_alpha_func + instance.inputs['DestBlendFunc'].default_value = str(shader.dest_blend) + instance.inputs['PriGradient'].default_value = str(shader.pri_gradient) + instance.inputs['SecGradient'].default_value = str(shader.sec_gradient) + instance.inputs['SrcBlendFunc'].default_value = str(shader.src_blend) + instance.inputs['Texturing'].default_value = str(shader.texturing) + instance.inputs['DetailColorFunc'].default_value = str(shader.detail_color_func) + instance.inputs['DetailAlphaFunc'].default_value = str(shader.detail_alpha_func) instance.inputs['Preset'].default_value = shader.shader_preset - instance.inputs['AlphaTest'].default_value = shader.alpha_test - instance.inputs['PostDetailColorFunc'].default_value = shader.post_detail_color_func - instance.inputs['PostDetailAlphaFunc'].default_value = shader.post_detail_alpha_func + instance.inputs['AlphaTest'].default_value = str(shader.alpha_test) + instance.inputs['PostDetailColorFunc'].default_value = str(shader.post_detail_color_func) + instance.inputs['PostDetailAlphaFunc'].default_value = str(shader.post_detail_alpha_func) return instance @@ -84,7 +83,7 @@ def register(name): group_inputs = group.nodes.new('NodeGroupInput') group_inputs.location = (-350,0) - # group.inputs.new('NodeSocketEnumMaterialAttributes', 'Attributes') + group.inputs.new('NodeSocketEnumMaterialAttributes', 'Attributes') group.inputs.new('NodeSocketString', 'VM_ARGS_0') group.inputs.new('NodeSocketString', 'VM_ARGS_1') group.inputs.new('NodeSocketColor', 'Diffuse') @@ -101,21 +100,21 @@ def register(name): group.inputs.new('NodeSocketFloat', 'Opacity') group.inputs.new('NodeSocketFloat', 'Translucency') - #group.inputs.new('NodeSocketEnumDepthCompare', 'DepthCompare') - #group.inputs.new('NodeSocketEnumDepthMaskWrite', 'DepthMaskWrite') + group.inputs.new('NodeSocketEnumDepthCompare', 'DepthCompare') + group.inputs.new('NodeSocketEnumDepthMaskWrite', 'DepthMaskWrite') VertexMaterialGroup.addInputInt(group, 'ColorMask') # obsolete (w3d_file.h) VertexMaterialGroup.addInputInt(group, 'FogFunc') # obsolete (w3d_file.h) - #group.inputs.new('NodeSocketEnumDestBlendFunc', 'DestBlendFunc') - #group.inputs.new('NodeSocketEnumPriGradient', 'PriGradient') - #group.inputs.new('NodeSocketEnumSecGradient', 'SecGradient') - #group.inputs.new('NodeSocketEnumSrcBlendFunc', 'SrcBlendFunc') - #group.inputs.new('NodeSocketEnumTexturing', 'Texturing') - #group.inputs.new('NodeSocketEnumDetailColorFunc', 'DetailColorFunc') - #group.inputs.new('NodeSocketEnumDetailAlphaFunc', 'DetailAlphaFunc') + group.inputs.new('NodeSocketEnumDestBlendFunc', 'DestBlendFunc') + group.inputs.new('NodeSocketEnumPriGradient', 'PriGradient') + group.inputs.new('NodeSocketEnumSecGradient', 'SecGradient') + group.inputs.new('NodeSocketEnumSrcBlendFunc', 'SrcBlendFunc') + group.inputs.new('NodeSocketEnumTexturing', 'Texturing') + group.inputs.new('NodeSocketEnumDetailColorFunc', 'DetailColorFunc') + group.inputs.new('NodeSocketEnumDetailAlphaFunc', 'DetailAlphaFunc') VertexMaterialGroup.addInputInt(group, 'Preset') # obsolete (w3d_file.h) - #group.inputs.new('NodeSocketEnumAlphaTest', 'AlphaTest') - #group.inputs.new('NodeSocketEnumDetailColorFunc', 'PostDetailColorFunc') - #group.inputs.new('NodeSocketEnumDetailAlphaFunc', 'PostDetailAlphaFunc') + group.inputs.new('NodeSocketEnumAlphaTest', 'AlphaTest') + group.inputs.new('NodeSocketEnumDetailColorFunc', 'PostDetailColorFunc') + group.inputs.new('NodeSocketEnumDetailAlphaFunc', 'PostDetailAlphaFunc') # create group outputs group_outputs = group.nodes.new('NodeGroupOutput') @@ -128,7 +127,7 @@ def register(name): alpha_pipeline.node_tree = bpy.data.node_groups['AlphaPipeline'] links.new(group_inputs.outputs['DiffuseTexture'], alpha_pipeline.inputs['Diffuse']) links.new(group_inputs.outputs['DiffuseTextureAlpha'], alpha_pipeline.inputs['Alpha']) - #links.new(group_inputs.outputs['AlphaTest'], alpha_pipeline.inputs['DestBlend']) + links.new(group_inputs.outputs['AlphaTest'], alpha_pipeline.inputs['DestBlend']) shader = node_tree.nodes.new('ShaderNodeEeveeSpecular') shader.label = 'Shader' @@ -141,3 +140,7 @@ def register(name): links.new(group_inputs.outputs['Emissive'], shader.inputs['Emissive Color']) links.new(alpha_pipeline.outputs['Alpha'], shader.inputs['Transparency']) links.new(shader.outputs['BSDF'], group_outputs.inputs['BSDF']) + + @staticmethod + def unregister(name): + bpy.data.node_groups.remove(name) diff --git a/io_mesh_w3d/common/structs/mesh_structs/shader_material.py b/io_mesh_w3d/common/structs/mesh_structs/shader_material.py index f211e25b..43859711 100644 --- a/io_mesh_w3d/common/structs/mesh_structs/shader_material.py +++ b/io_mesh_w3d/common/structs/mesh_structs/shader_material.py @@ -258,3 +258,12 @@ def create(self, parent): constants = create_node(fx_shader, 'Constants') for prop in self.properties: prop.create(constants) + + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + else: + return False + + def __ne__(self, other): + return not self.__eq__(other) diff --git a/io_mesh_w3d/common/structs/mesh_structs/texture.py b/io_mesh_w3d/common/structs/mesh_structs/texture.py index 7ce6328b..550e37ad 100644 --- a/io_mesh_w3d/common/structs/mesh_structs/texture.py +++ b/io_mesh_w3d/common/structs/mesh_structs/texture.py @@ -34,6 +34,15 @@ def write(self, io_stream): write_ulong(self.frame_count, io_stream) write_float(self.frame_rate, io_stream) + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + else: + return False + + def __ne__(self, other): + return not self.__eq__(other) + W3D_CHUNK_TEXTURE = 0x00000031 W3D_CHUNK_TEXTURE_NAME = 0x00000032 @@ -87,3 +96,12 @@ def create(self, parent): texture = create_node(parent, 'Texture') texture.set('id', self.id) texture.set('File', self.file) + + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + else: + return False + + def __ne__(self, other): + return not self.__eq__(other) diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index f324467c..8eba23ff 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -7,6 +7,7 @@ from io_mesh_w3d.common.shading.vertex_material_group import * from io_mesh_w3d.common.utils.helpers import * +from io_mesh_w3d.w3d.structs.mesh_structs.prelit import PrelitBase from io_mesh_w3d.w3d.structs.mesh_structs.vertex_material import * from io_mesh_w3d.common.structs.mesh_structs.shader_material import * @@ -76,62 +77,66 @@ def expand(ids, count): return ids -def create_materials(context, mesh_struct, mesh, triangles): +def create_materials(context, structs, mesh, triangles): b_mesh = bmesh.new() b_mesh.from_mesh(mesh) num_faces = len(triangles) face_pipeline_sets = [None] * num_faces - for i, mat_pass in enumerate(mesh_struct.material_passes): - vert_mat_ids = [None] * num_faces - shader_ids = [None] * num_faces - texture_ids = [] - uv_maps = [] - shader_mat_ids = [None] * num_faces + for struct in structs: + if struct is None: + continue - if mat_pass.vertex_material_ids: - vert_mat_ids = expand(mat_pass.vertex_material_ids, num_faces) + for i, mat_pass in enumerate(struct.material_passes): + vert_mat_ids = [None] * num_faces + shader_ids = [None] * num_faces + texture_ids = [] + uv_maps = [] + shader_mat_ids = [None] * num_faces - if mat_pass.shader_ids: - shader_ids = expand(mat_pass.shader_ids, num_faces) + if mat_pass.vertex_material_ids: + vert_mat_ids = expand(mat_pass.vertex_material_ids, num_faces) - if mat_pass.shader_material_ids: - shader_mat_ids = expand(mat_pass.shader_material_ids, num_faces) + if mat_pass.shader_ids: + shader_ids = expand(mat_pass.shader_ids, num_faces) - if mat_pass.tx_coords: - uv_maps = get_or_create_uv_layer(mesh, b_mesh, triangles, mat_pass.tx_coords) + if mat_pass.shader_material_ids: + shader_mat_ids = expand(mat_pass.shader_material_ids, num_faces) - for tx_stage in mat_pass.tx_stages: - for tx_coords in tx_stage.tx_coords: - uv_maps.append(get_or_create_uv_layer(mesh, b_mesh, triangles, tx_coords)) + if mat_pass.tx_coords: + uv_maps = get_or_create_uv_layer(mesh, b_mesh, triangles, mat_pass.tx_coords) - for k, tx_ids in enumerate(tx_stage.tx_ids): - tex_ids = expand(tx_ids, num_faces) - uv_map = uv_maps[k] + for tx_stage in mat_pass.tx_stages: + for tx_coords in tx_stage.tx_coords: + uv_maps.append(get_or_create_uv_layer(mesh, b_mesh, triangles, tx_coords)) + + for k, tx_ids in enumerate(tx_stage.tx_ids): + tex_ids = expand(tx_ids, num_faces) + uv_map = uv_maps[k] + for j, tri in enumerate(triangles): + pipeline = Pipeline(type='vertex', pass_index=i) + pipeline.vert_mat = struct.vert_materials[vert_mat_ids[j]] + pipeline.shader = struct.shaders[shader_ids[j]] + pipeline.texture = struct.textures[tex_ids[j]] + pipeline.uv_map = uv_map + + if face_pipeline_sets[j] is None: + face_pipeline_sets[j] = PipelineSet() + face_pipeline_sets[j].add(pipeline) + + if not isinstance(struct, PrelitBase) and struct.shader_materials: for j, tri in enumerate(triangles): - pipeline = Pipeline(type='vertex', pass_index=i) - pipeline.vert_mat = mesh_struct.vert_materials[vert_mat_ids[j]] - pipeline.shader = mesh_struct.shaders[shader_ids[j]] - pipeline.texture = mesh_struct.textures[tex_ids[j]] - pipeline.uv_map = uv_map + pipeline = Pipeline( + type='shader', + pass_index=i, + shader_mat=struct.shader_materials[shader_mat_ids[j]], + uv_map=uv_maps) if face_pipeline_sets[j] is None: face_pipeline_sets[j] = PipelineSet() face_pipeline_sets[j].add(pipeline) - if not mat_pass.tx_stages: - for j, tri in enumerate(triangles): - pipeline = Pipeline( - type='shader', - pass_index=i, - shader_mat=mesh_struct.shader_materials[shader_mat_ids[j]], - uv_map=uv_maps) - - if face_pipeline_sets[j] is None: - face_pipeline_sets[j] = PipelineSet() - face_pipeline_sets[j].add(pipeline) - unique_pipeline_sets = [] face_mat_indices = [0] * num_faces @@ -162,9 +167,13 @@ def create_material(context, mesh, b_mesh, triangles, pps): node_tree = material.node_tree node_tree.nodes.remove(node_tree.nodes.get('Principled BSDF')) + vert_ = dict() + uv_nodes = dict() + uv_tex_combos = dict() + for pipeline in pps.pipelines: if pipeline.type == 'vertex': - create_vertex_material_pipeline(context, node_tree, pipeline) + create_vertex_material_pipeline(context, node_tree, pipeline, vert_, uv_nodes, uv_tex_combos) else: create_shader_material_pipeline(context, node_tree, pipeline) @@ -173,11 +182,12 @@ def create_material(context, mesh, b_mesh, triangles, pps): # vertex material ########################################################################## -def create_vertex_material_pipeline(context, node_tree, pipeline): +def create_vertex_material_pipeline(context, node_tree, pipeline, vert_, uv_nodes, uv_tex_combos): instance = VertexMaterialGroup.create(node_tree, pipeline.vert_mat, pipeline.shader) instance.label = pipeline.vert_mat.vm_name instance.location = (0, 300) instance.width = 200 + instance.hide = True output = node_tree.nodes.get('Material Output') @@ -185,17 +195,27 @@ def create_vertex_material_pipeline(context, node_tree, pipeline): links.new(instance.outputs['BSDF'], output.inputs['Surface']) if pipeline.texture is not None: - texture = find_texture(context, pipeline.texture.file, pipeline.texture.id) + if (pipeline.uv_map, pipeline.texture.file) in uv_tex_combos: + texture_node = uv_tex_combos[(pipeline.uv_map, pipeline.texture.file)] + else: + texture = find_texture(context, pipeline.texture.file, pipeline.texture.id) + texture_node = node_tree.nodes.new('ShaderNodeTexImage') + texture_node.image = texture + texture_node.location = (-350, 300 * (-len(uv_tex_combos) + 1)) + texture_node.hide = True + uv_tex_combos[(pipeline.uv_map, pipeline.texture.file)] = texture_node - texture_node = node_tree.nodes.new('ShaderNodeTexImage') - texture_node.image = texture - texture_node.location = (-350, 300) links.new(texture_node.outputs['Color'], instance.inputs['DiffuseTexture']) links.new(texture_node.outputs['Alpha'], instance.inputs['DiffuseTextureAlpha']) - uv_node = node_tree.nodes.new('ShaderNodeUVMap') - uv_node.location = (-550, 300) - uv_node.uv_map = pipeline.uv_map + if pipeline.uv_map in uv_nodes: + uv_node = uv_nodes[pipeline.uv_map] + else: + uv_node = node_tree.nodes.new('ShaderNodeUVMap') + uv_node.location = (-550, 300 * (-len(uv_nodes) + 1)) + uv_node.uv_map = pipeline.uv_map + uv_nodes[pipeline.uv_map] = uv_node + links.new(uv_node.outputs['UV'], texture_node.inputs['Vector']) diff --git a/io_mesh_w3d/common/utils/mesh_import.py b/io_mesh_w3d/common/utils/mesh_import.py index 9f7ecf87..4756f439 100644 --- a/io_mesh_w3d/common/utils/mesh_import.py +++ b/io_mesh_w3d/common/utils/mesh_import.py @@ -35,7 +35,9 @@ def create_mesh(context, mesh_struct, coll): if mesh_struct.is_hidden(): mesh_ob.hide_set(True) - create_materials(context, mesh_struct, mesh, triangles) + structs = [mesh_struct, mesh_struct.prelit_unlit, mesh_struct.prelit_vertex, + mesh_struct.prelit_lightmap_multi_pass, mesh_struct.prelit_lightmap_multi_texture] + create_materials(context, structs, mesh, triangles) def rig_mesh(mesh_struct, hierarchy, rig, sub_object=None): diff --git a/io_mesh_w3d/common/utils/node_group_creator.py b/io_mesh_w3d/common/utils/node_group_creator.py index 2611ab23..0c432a85 100644 --- a/io_mesh_w3d/common/utils/node_group_creator.py +++ b/io_mesh_w3d/common/utils/node_group_creator.py @@ -163,3 +163,14 @@ def create(self, directory, file, node_tree=None): else: print('node type: ' + xml_node.tag + ' is not supported') return nodes + + + def unregister(self, directory, file): + path = os.path.join(directory, file) + root = find_root(None, path) + if root is None: + return + + name = root.get('name') + if name in bpy.data.node_groups: + bpy.data.node_groups.remove(name) \ No newline at end of file diff --git a/io_mesh_w3d/w3d/structs/mesh_structs/shader.py b/io_mesh_w3d/w3d/structs/mesh_structs/shader.py index 9412d68c..02dbcf09 100644 --- a/io_mesh_w3d/w3d/structs/mesh_structs/shader.py +++ b/io_mesh_w3d/w3d/structs/mesh_structs/shader.py @@ -69,5 +69,11 @@ def write(self, io_stream): write_ubyte(self.post_detail_alpha_func, io_stream) write_ubyte(self.pad, io_stream) + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + else: + return False + def __ne__(self, other): return not self.__eq__(other) \ No newline at end of file diff --git a/io_mesh_w3d/w3d/structs/mesh_structs/vertex_material.py b/io_mesh_w3d/w3d/structs/mesh_structs/vertex_material.py index 606b86d4..2fd3c5ad 100644 --- a/io_mesh_w3d/w3d/structs/mesh_structs/vertex_material.py +++ b/io_mesh_w3d/w3d/structs/mesh_structs/vertex_material.py @@ -52,6 +52,15 @@ def write(self, io_stream): write_float(self.opacity, io_stream) write_float(self.translucency, io_stream) + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + else: + return False + + def __ne__(self, other): + return not self.__eq__(other) + W3D_CHUNK_VERTEX_MATERIAL = 0x0000002B W3D_CHUNK_VERTEX_MATERIAL_NAME = 0x0000002C @@ -109,3 +118,12 @@ def write(self, io_stream): if self.vm_args_1 is not '': write_chunk_head(W3D_CHUNK_VERTEX_MAPPER_ARGS1, io_stream, text_size(self.vm_args_1, False)) write_string(self.vm_args_1, io_stream) + + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + else: + return False + + def __ne__(self, other): + return not self.__eq__(other) From 5b41e6bd877c27fab89b3bd9d1aef153158605ee Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Fri, 24 Apr 2020 00:05:01 +0200 Subject: [PATCH 58/62] fixed vertex_material_group --- io_mesh_w3d/__init__.py | 2 +- io_mesh_w3d/common/shading/node_socket_enum.py | 12 ++++++++---- io_mesh_w3d/common/shading/vertex_material_group.py | 2 ++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/io_mesh_w3d/__init__.py b/io_mesh_w3d/__init__.py index 90664a98..b86eb867 100644 --- a/io_mesh_w3d/__init__.py +++ b/io_mesh_w3d/__init__.py @@ -269,7 +269,7 @@ def draw(self, context): NodeSocketEnum, NodeSocketEnumMaterialAttributes, NodeSocketEnumDepthCompare, - NodeSocketEnumDepthmaskWrite, + NodeSocketEnumDepthMaskWrite, NodeSocketEnumAlphatest, NodeSocketEnumDestBlendFunc, NodeSocketEnumPriGradient, diff --git a/io_mesh_w3d/common/shading/node_socket_enum.py b/io_mesh_w3d/common/shading/node_socket_enum.py index c8d71b96..5a18fc10 100644 --- a/io_mesh_w3d/common/shading/node_socket_enum.py +++ b/io_mesh_w3d/common/shading/node_socket_enum.py @@ -30,7 +30,7 @@ def draw_color(self, context, node): class NodeSocketEnumMaterialAttributes(NodeSocketEnum): - bl_idname = 'NodeSocketMaterialAttributes' + bl_idname = 'NodeSocketEnumMaterialAttributes' bl_label = 'Material Attributes Enum Flag Node Socket' default_value: bpy.props.EnumProperty( @@ -65,8 +65,8 @@ class NodeSocketEnumDepthCompare(NodeSocketEnum): default='3') -class NodeSocketEnumDepthmaskWrite(NodeSocketEnum): - bl_idname = 'NodeSocketEnumDepthmaskWrite' +class NodeSocketEnumDepthMaskWrite(NodeSocketEnum): + bl_idname = 'NodeSocketEnumDepthMaskWrite' bl_label = 'Depthmask Write Enum Node Socket' default_value: bpy.props.EnumProperty( @@ -182,7 +182,11 @@ class NodeSocketEnumDetailColorFunc(NodeSocketEnum): ('5', 'SUB', 'local - other'), ('6', 'SUBR', 'other - local'), ('7', 'BLEND', '(localAlpha)*local + (~localAlpha)*other'), - ('8', 'DETAILBLEND', '(otherAlpha)*local + (~otherAlpha)*other')], + ('8', 'DETAILBLEND', '(otherAlpha)*local + (~otherAlpha)*other'), + ('9', '9_UNKNOWN', 'unknown'), + ('10', '10_UNKNOWN', 'unknown'), + ('11', '11_UNKNOWN', 'unknown'), + ('12', '12_UNKNOWN', 'unknown')], default='0') diff --git a/io_mesh_w3d/common/shading/vertex_material_group.py b/io_mesh_w3d/common/shading/vertex_material_group.py index 5553ddfd..ecc71e45 100644 --- a/io_mesh_w3d/common/shading/vertex_material_group.py +++ b/io_mesh_w3d/common/shading/vertex_material_group.py @@ -116,6 +116,8 @@ def register(name): group.inputs.new('NodeSocketEnumDetailColorFunc', 'PostDetailColorFunc') group.inputs.new('NodeSocketEnumDetailAlphaFunc', 'PostDetailAlphaFunc') + print('created') + # create group outputs group_outputs = group.nodes.new('NodeGroupOutput') group_outputs.location = (300,0) From 3dc94e2d8a553d5149eba4509bc57288cde4a9af Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Fri, 24 Apr 2020 18:47:51 +0200 Subject: [PATCH 59/62] small changes --- .../common/shading/node_socket_enum.py | 2 +- io_mesh_w3d/common/utils/material_import.py | 20 ++++++++++++------- .../w3d/structs/mesh_structs/prelit.py | 3 +-- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/io_mesh_w3d/common/shading/node_socket_enum.py b/io_mesh_w3d/common/shading/node_socket_enum.py index 5a18fc10..3cc1c3b9 100644 --- a/io_mesh_w3d/common/shading/node_socket_enum.py +++ b/io_mesh_w3d/common/shading/node_socket_enum.py @@ -186,7 +186,7 @@ class NodeSocketEnumDetailColorFunc(NodeSocketEnum): ('9', '9_UNKNOWN', 'unknown'), ('10', '10_UNKNOWN', 'unknown'), ('11', '11_UNKNOWN', 'unknown'), - ('12', '12_UNKNOWN', 'unknown')], + ('12', 'MOD_ALPHA_ADD_COLOR', 'unknown')], default='0') diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index 8eba23ff..949a2dd4 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -111,15 +111,21 @@ def create_materials(context, structs, mesh, triangles): for tx_coords in tx_stage.tx_coords: uv_maps.append(get_or_create_uv_layer(mesh, b_mesh, triangles, tx_coords)) + type = 'vertex' + if isinstance(struct, PrelitBase): + type += '_' + str(struct.type) + for k, tx_ids in enumerate(tx_stage.tx_ids): tex_ids = expand(tx_ids, num_faces) uv_map = uv_maps[k] for j, tri in enumerate(triangles): - pipeline = Pipeline(type='vertex', pass_index=i) - pipeline.vert_mat = struct.vert_materials[vert_mat_ids[j]] - pipeline.shader = struct.shaders[shader_ids[j]] - pipeline.texture = struct.textures[tex_ids[j]] - pipeline.uv_map = uv_map + pipeline = Pipeline( + type=type, + pass_index=i, + vert_mat=struct.vert_materials[vert_mat_ids[j]], + shader=struct.shaders[shader_ids[j]], + texture=struct.textures[tex_ids[j]], + uv_map=uv_map) if face_pipeline_sets[j] is None: face_pipeline_sets[j] = PipelineSet() @@ -172,7 +178,7 @@ def create_material(context, mesh, b_mesh, triangles, pps): uv_tex_combos = dict() for pipeline in pps.pipelines: - if pipeline.type == 'vertex': + if 'vertex' in pipeline.type: create_vertex_material_pipeline(context, node_tree, pipeline, vert_, uv_nodes, uv_tex_combos) else: create_shader_material_pipeline(context, node_tree, pipeline) @@ -184,7 +190,7 @@ def create_material(context, mesh, b_mesh, triangles, pps): def create_vertex_material_pipeline(context, node_tree, pipeline, vert_, uv_nodes, uv_tex_combos): instance = VertexMaterialGroup.create(node_tree, pipeline.vert_mat, pipeline.shader) - instance.label = pipeline.vert_mat.vm_name + instance.label = pipeline.vert_mat.vm_name + '_' + str(pipeline.pass_index) + '_' + str(pipeline.type) instance.location = (0, 300) instance.width = 200 instance.hide = True diff --git a/io_mesh_w3d/w3d/structs/mesh_structs/prelit.py b/io_mesh_w3d/w3d/structs/mesh_structs/prelit.py index b080fe60..480bdf9b 100644 --- a/io_mesh_w3d/w3d/structs/mesh_structs/prelit.py +++ b/io_mesh_w3d/w3d/structs/mesh_structs/prelit.py @@ -75,8 +75,7 @@ def write(self, io_stream): write_list(self.vert_materials, io_stream, VertexMaterial.write) if self.shaders: - write_chunk_head(W3D_CHUNK_SHADERS, io_stream, - list_size(self.shaders, False)) + write_chunk_head(W3D_CHUNK_SHADERS, io_stream, list_size(self.shaders, False)) write_list(self.shaders, io_stream, Shader.write) if self.textures: From de8f0b50db39416999b48127193d52915108e698 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Fri, 24 Apr 2020 20:07:43 +0200 Subject: [PATCH 60/62] this whole node stuff is still crap... --- .../common/shading/node_socket_enum.py | 17 +++++++----- .../common/shading/node_socket_texture.py | 8 ++++++ .../common/shading/node_socket_vec2.py | 4 +-- .../common/shading/node_socket_vec4.py | 4 +-- .../common/shading/vertex_material_group.py | 4 ++- io_mesh_w3d/common/utils/material_import.py | 1 + .../common/utils/node_group_creator.py | 11 ++++++++ .../node_group_templates/alpha_pipeline.xml | 27 ++++++++++--------- 8 files changed, 51 insertions(+), 25 deletions(-) diff --git a/io_mesh_w3d/common/shading/node_socket_enum.py b/io_mesh_w3d/common/shading/node_socket_enum.py index 3cc1c3b9..ec8f5834 100644 --- a/io_mesh_w3d/common/shading/node_socket_enum.py +++ b/io_mesh_w3d/common/shading/node_socket_enum.py @@ -10,14 +10,14 @@ class NodeSocketEnum(NodeSocket): bl_label = 'Enum Node Socket' default_value: bpy.props.EnumProperty( - name="Direction", - description="Just an example", + name='Direction', + description='Just an example', items=[ - ('DOWN', "Down", "Where your feet are"), - ('UP', "Up", "Where your head should be"), - ('LEFT', "Left", "Not right"), - ('RIGHT', "Right", "Not left")], - default='UP') + ('0', 'DOWN', 'Where your feet are'), + ('1', 'UP', 'Where your head should be'), + ('2', 'LEFT', 'Not right'), + ('3', 'RIGHT', 'Not left')], + default='0') def draw(self, context, layout, node, text): if self.is_output or self.is_linked: @@ -28,6 +28,9 @@ def draw(self, context, layout, node, text): def draw_color(self, context, node): return (1.0, 0.4, 0.216, 0.5) + def get(self): + return int(self.default_value) + class NodeSocketEnumMaterialAttributes(NodeSocketEnum): bl_idname = 'NodeSocketEnumMaterialAttributes' diff --git a/io_mesh_w3d/common/shading/node_socket_texture.py b/io_mesh_w3d/common/shading/node_socket_texture.py index 6e54c393..2a681d53 100644 --- a/io_mesh_w3d/common/shading/node_socket_texture.py +++ b/io_mesh_w3d/common/shading/node_socket_texture.py @@ -5,10 +5,18 @@ from bpy.types import NodeSocketColor +# This does not work atm (blender 2.82a) class NodeSocketTexture(NodeSocketColor): bl_idname = 'NodeSocketTexture' bl_label = 'Texture Node Socket' + default_value: bpy.props.FloatVectorProperty( + name='texture', + subtype='COLOR', + size=4, + default=(0.0, 0.0, 0.0, 0.0), + description='Texture') + def draw(self, context, layout, node, text): layout.label(text=text) diff --git a/io_mesh_w3d/common/shading/node_socket_vec2.py b/io_mesh_w3d/common/shading/node_socket_vec2.py index f67dbbd3..8dd14c1a 100644 --- a/io_mesh_w3d/common/shading/node_socket_vec2.py +++ b/io_mesh_w3d/common/shading/node_socket_vec2.py @@ -9,7 +9,7 @@ class NodeSocketVector2(NodeSocket): bl_idname = 'NodeSocketVector2' bl_label = 'Vector2 Node Socket' - vec2_prop: bpy.props.FloatVectorProperty( + default_value: bpy.props.FloatVectorProperty( name='Vector2', subtype='TRANSLATION', size=2, @@ -21,7 +21,7 @@ def draw(self, context, layout, node, text): if self.is_output or self.is_linked: layout.label(text=text) else: - layout.prop(self, "vec2_prop", text=text) + layout.prop(self, 'default_value', text=text) def draw_color(self, context, node): return (1.0, 0.4, 0.216, 0.5) diff --git a/io_mesh_w3d/common/shading/node_socket_vec4.py b/io_mesh_w3d/common/shading/node_socket_vec4.py index 4ccaa2be..8a5f3e60 100644 --- a/io_mesh_w3d/common/shading/node_socket_vec4.py +++ b/io_mesh_w3d/common/shading/node_socket_vec4.py @@ -9,7 +9,7 @@ class NodeSocketVector4(NodeSocket): bl_idname = 'NodeSocketVector4' bl_label = 'Vector4 Node Socket' - vec2_prop: bpy.props.FloatVectorProperty( + default_value: bpy.props.FloatVectorProperty( name='Vector4', subtype='TRANSLATION', size=4, @@ -21,7 +21,7 @@ def draw(self, context, layout, node, text): if self.is_output or self.is_linked: layout.label(text=text) else: - layout.prop(self, "vec2_prop", text=text) + layout.prop(self, 'default_value', text=text) def draw_color(self, context, node): return (1.0, 0.4, 0.216, 0.5) diff --git a/io_mesh_w3d/common/shading/vertex_material_group.py b/io_mesh_w3d/common/shading/vertex_material_group.py index ecc71e45..6bd52def 100644 --- a/io_mesh_w3d/common/shading/vertex_material_group.py +++ b/io_mesh_w3d/common/shading/vertex_material_group.py @@ -88,7 +88,8 @@ def register(name): group.inputs.new('NodeSocketString', 'VM_ARGS_1') group.inputs.new('NodeSocketColor', 'Diffuse') group.inputs['Diffuse'].default_value = (0.8, 0.8, 0.8, 1.0) - group.inputs.new('NodeSocketTexture', 'DiffuseTexture') + group.inputs.new('NodeSocketColor', 'DiffuseTexture') + group.inputs['DiffuseTexture'].default_value = (0.0, 0.0, 0.0, 0.0) group.inputs.new('NodeSocketTextureAlpha', 'DiffuseTextureAlpha') group.inputs.new('NodeSocketColor', 'Ambient') group.inputs['Ambient'].default_value = (0.8, 0.8, 0.8, 1.0) @@ -105,6 +106,7 @@ def register(name): VertexMaterialGroup.addInputInt(group, 'ColorMask') # obsolete (w3d_file.h) VertexMaterialGroup.addInputInt(group, 'FogFunc') # obsolete (w3d_file.h) group.inputs.new('NodeSocketEnumDestBlendFunc', 'DestBlendFunc') + group.inputs.new('NodeSocketInt', 'DestBlendFunc') group.inputs.new('NodeSocketEnumPriGradient', 'PriGradient') group.inputs.new('NodeSocketEnumSecGradient', 'SecGradient') group.inputs.new('NodeSocketEnumSrcBlendFunc', 'SrcBlendFunc') diff --git a/io_mesh_w3d/common/utils/material_import.py b/io_mesh_w3d/common/utils/material_import.py index 949a2dd4..98fe416d 100644 --- a/io_mesh_w3d/common/utils/material_import.py +++ b/io_mesh_w3d/common/utils/material_import.py @@ -211,6 +211,7 @@ def create_vertex_material_pipeline(context, node_tree, pipeline, vert_, uv_node texture_node.hide = True uv_tex_combos[(pipeline.uv_map, pipeline.texture.file)] = texture_node + print(instance.inputs['DiffuseTexture'].type) links.new(texture_node.outputs['Color'], instance.inputs['DiffuseTexture']) links.new(texture_node.outputs['Alpha'], instance.inputs['DiffuseTextureAlpha']) diff --git a/io_mesh_w3d/common/utils/node_group_creator.py b/io_mesh_w3d/common/utils/node_group_creator.py index 0c432a85..60a8f500 100644 --- a/io_mesh_w3d/common/utils/node_group_creator.py +++ b/io_mesh_w3d/common/utils/node_group_creator.py @@ -19,6 +19,16 @@ def process_input_hides(self, xml_node, node): else: node.outputs[id].hide = True + def process_value_setups(self, xml_node, node): + for child_node in xml_node: + if child_node.tag != 'set': + continue + id = int(child_node.get('id')) + value = child_node.get('value') + socket = node.inputs[id] + type = socket.type + self.process_default_value(socket, type, value) + def process_default_value(self, socket, type, default): if default is None: @@ -121,6 +131,7 @@ def create(self, directory, file, node_tree=None): nodes[xml_node.get('name')] = node self.process_input_hides(xml_node, node) + self.process_value_setups(xml_node, node) if type == 'NodeGroupInput': self.create_input_node(node_tree, xml_node, node) diff --git a/io_mesh_w3d/node_group_templates/alpha_pipeline.xml b/io_mesh_w3d/node_group_templates/alpha_pipeline.xml index 2cdcb880..ee0db232 100644 --- a/io_mesh_w3d/node_group_templates/alpha_pipeline.xml +++ b/io_mesh_w3d/node_group_templates/alpha_pipeline.xml @@ -6,27 +6,28 @@ - - + + - - - + + - - - - - + + + + + + + - - + + - + From 4f0a175ef4a1135058bf518c4024df346778c92c Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Mon, 29 Jun 2020 22:53:03 +0200 Subject: [PATCH 61/62] got custom node sockets working!!! --- io_mesh_w3d/__init__.py | 5 +++-- io_mesh_w3d/common/shading/node_socket_texture.py | 11 ++++++++++- io_mesh_w3d/common/utils/node_group_creator.py | 3 +++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/io_mesh_w3d/__init__.py b/io_mesh_w3d/__init__.py index b86eb867..36ade618 100644 --- a/io_mesh_w3d/__init__.py +++ b/io_mesh_w3d/__init__.py @@ -258,7 +258,7 @@ def draw(self, context): col.prop(context.active_bone, 'visibility') -from io_mesh_w3d.common.shading.node_socket_texture import NodeSocketTexture +from io_mesh_w3d.common.shading.node_socket_texture import NodeSocketTexture, NodeSocketInterfaceTexture from io_mesh_w3d.common.shading.node_socket_texture_alpha import NodeSocketTextureAlpha from io_mesh_w3d.common.shading.node_socket_vec2 import NodeSocketVector2 from io_mesh_w3d.common.shading.node_socket_vec4 import NodeSocketVector4 @@ -266,6 +266,8 @@ def draw(self, context): CLASSES = ( + NodeSocketTexture, + NodeSocketInterfaceTexture, NodeSocketEnum, NodeSocketEnumMaterialAttributes, NodeSocketEnumDepthCompare, @@ -278,7 +280,6 @@ def draw(self, context): NodeSocketEnumTexturing, NodeSocketEnumDetailColorFunc, NodeSocketEnumDetailAlphaFunc, - NodeSocketTexture, NodeSocketTextureAlpha, NodeSocketVector2, NodeSocketVector4, diff --git a/io_mesh_w3d/common/shading/node_socket_texture.py b/io_mesh_w3d/common/shading/node_socket_texture.py index 2a681d53..88e8086c 100644 --- a/io_mesh_w3d/common/shading/node_socket_texture.py +++ b/io_mesh_w3d/common/shading/node_socket_texture.py @@ -2,7 +2,16 @@ # Written by Stephan Vedder and Michael Schnabel import bpy -from bpy.types import NodeSocketColor +from bpy.types import NodeSocketColor, NodeSocketInterfaceColor + +class NodeSocketInterfaceTexture(NodeSocketInterfaceColor): + bl_socket_idname = 'NodeSocketTexture' + + def draw(self, context, layout): + pass + + def draw_color(self, context): + return (1.0, 0.4, 0.216, 0.5) # This does not work atm (blender 2.82a) diff --git a/io_mesh_w3d/common/utils/node_group_creator.py b/io_mesh_w3d/common/utils/node_group_creator.py index 60a8f500..9a7283aa 100644 --- a/io_mesh_w3d/common/utils/node_group_creator.py +++ b/io_mesh_w3d/common/utils/node_group_creator.py @@ -86,6 +86,9 @@ def create_input_node(self, node_tree, xml_node, node): name = child_node.get('name') socket = node_tree.inputs.new(type, name) + if (type == 'NodeSocketTexture'): + print(socket) + socket.default_value self.process_presets(socket, type, child_node, name) From 181c9e560e6dd09ff5c8bec911f40cc04bd26474 Mon Sep 17 00:00:00 2001 From: Michael Schnabel Date: Tue, 30 Jun 2020 21:08:35 +0200 Subject: [PATCH 62/62] working example for default_value --- io_mesh_w3d/common/shading/node_socket_texture.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/io_mesh_w3d/common/shading/node_socket_texture.py b/io_mesh_w3d/common/shading/node_socket_texture.py index 88e8086c..d0344715 100644 --- a/io_mesh_w3d/common/shading/node_socket_texture.py +++ b/io_mesh_w3d/common/shading/node_socket_texture.py @@ -7,6 +7,8 @@ class NodeSocketInterfaceTexture(NodeSocketInterfaceColor): bl_socket_idname = 'NodeSocketTexture' + default_value = [0.0, 0.0, 0.0, 0.0] + def draw(self, context, layout): pass