diff --git a/.gitignore b/.gitignore index 8fc240cc..33a999db 100644 --- a/.gitignore +++ b/.gitignore @@ -112,3 +112,6 @@ dmypy.json # Pyre type checker .pyre/ + +# Blender Project backups +*.blend1 \ No newline at end of file diff --git a/assets/sycreation-s-default.blend b/assets/sycreation-s-default.blend index f921442e..cc1dfbf8 100644 Binary files a/assets/sycreation-s-default.blend and b/assets/sycreation-s-default.blend differ diff --git a/bpy_utilities/material_loader/shaders/source1_shaders/detail.py b/bpy_utilities/material_loader/shaders/source1_shaders/detail.py index e4a05e7f..8409227a 100644 --- a/bpy_utilities/material_loader/shaders/source1_shaders/detail.py +++ b/bpy_utilities/material_loader/shaders/source1_shaders/detail.py @@ -54,13 +54,13 @@ def detailtexturetransform(self): return self._vavle_material.get_transform_matrix('$detailtexturetransform', {'center': (0.5, 0.5, 0), 'scale': (1.0, 1.0, 1), 'rotate': (0, 0, 0), 'translate': (0, 0, 0)}) def handle_detail(self, next_socket : bpy.types.NodeSocket, albedo_socket : bpy.types.NodeSocket, *, UV=None): - if (self.detailmode not in [0, 1, 2, 4, 5]): + if (self.detailmode not in [0, 1, 2, 3, 4, 5, 6, 7, 8]): logger.error(f'Failed to load detail: unhandled Detail mode, got' + str(self.detailmode)) return albedo_socket, None detailblend = self.create_node_group('$DetailBlendMode' + str(self.detailmode), [-500, -60], name='DetailBlend') detailblend.width = 210 detailblend.inputs['$detailblendfactor [float]'].default_value = self.detailfactor - if (self.detailmode == 5): + if (self.detailmode in [5, 6]): self.connect_nodes(detailblend.outputs['BSDF'], next_socket.node.outputs['BSDF'].links[0].to_socket) self.connect_nodes(next_socket.node.outputs['BSDF'], detailblend.inputs[0]) else: @@ -70,7 +70,7 @@ def handle_detail(self, next_socket : bpy.types.NodeSocket, albedo_socket : bpy. detailblend.inputs['$detail [texture]'], detailblend.inputs.get('$detail alpha [texture alpha]', None), name='$detail') - if (self.detailmode == 4): + if (self.detailmode in [4, 7]): self.connect_nodes(albedo_socket.node.outputs['Alpha'], detailblend.intputs['$basetexture alpha [texture alpha]']) detail.location = [-1100, -130] scale = self.create_node("ShaderNodeVectorMath") diff --git a/bpy_utilities/material_loader/shaders/source1_shaders/lightmap_generic.py b/bpy_utilities/material_loader/shaders/source1_shaders/lightmap_generic.py index 87627ce5..9d0aa701 100644 --- a/bpy_utilities/material_loader/shaders/source1_shaders/lightmap_generic.py +++ b/bpy_utilities/material_loader/shaders/source1_shaders/lightmap_generic.py @@ -1,8 +1,10 @@ + +from .detail import DetailSupportMixin from ...shader_base import Nodes from ..source1_shader_base import Source1ShaderBase -class LightmapGeneric(Source1ShaderBase): +class LightmapGeneric(DetailSupportMixin): SHADER = 'lightmappedgeneric' @property @@ -17,37 +19,107 @@ def basetexture(self): return self.load_texture_or_default(texture_path, (0.3, 0, 0.3, 1.0)) return None + @property + def basetexturetransform(self): + return self._vavle_material.get_transform_matrix('$basetexturetransform', {'center': (0.5, 0.5, 0), 'scale': (1.0, 1.0, 1), 'rotate': (0, 0, 0), 'translate': (0, 0, 0)}) + + @property + def ssbump(self): + return self._vavle_material.get_param('$ssbump', None) + @property def bumpmap(self): texture_path = self._vavle_material.get_param('$bumpmap', None) if texture_path is not None: - image = self.load_texture_or_default(texture_path, (0.6, 0.0, 0.6, 1.0)) + image = self.load_texture_or_default(texture_path, (0.5, 0.5, 1.0, 1.0)) if self.ssbump: image = self.convert_ssbump(image) + image = self.convert_normalmap(image) image.colorspace_settings.is_data = True image.colorspace_settings.name = 'Non-Color' return image return None @property - def ssbump(self): - return self._vavle_material.get_int('ssbump', 0) == 1 + def bumptransform(self): + return self._vavle_material.get_transform_matrix('$bumptransform', {'center': (0.5, 0.5, 0), 'scale': (1.0, 1.0, 1), 'rotate': (0, 0, 0), 'translate': (0, 0, 0)}) @property - def phong(self): - return self._vavle_material.get_int('$phong', 0) == 1 + def selfillummask(self): + texture_path = self._vavle_material.get_param('$selfillummask', None) + if texture_path is not None: + image = self.load_texture_or_default(texture_path, (0.0, 0.0, 0.0, 1.0)) + image.colorspace_settings.is_data = True + image.colorspace_settings.name = 'Non-Color' + return image + return None + + @property + def color(self): + color_value, value_type = self._vavle_material.get_vector('$color', None) + if color_value is None: + return None + divider = 255 if value_type is int else 1 + color_value = list(map(lambda a: a / divider, color_value)) + if len(color_value) == 1: + color_value = [color_value[0], color_value[0], color_value[0]] + return self.ensure_length(color_value, 4, 1.0) @property - def alpha(self): - return self._vavle_material.get_int('$alpha', 0) == 1 + def translucent(self): + return self._vavle_material.get_int('$translucent', 0) == 1 @property def alphatest(self): return self._vavle_material.get_int('$alphatest', 0) == 1 @property - def translucent(self): - return self._vavle_material.get_int('$translucent', 0) == 1 + def alphatestreference(self): + return self._vavle_material.get_float('$alphatestreference', 0.5) + + @property + def allowalphatocoverage(self): + return self._vavle_material.get_int('$allowalphatocoverage', 0) == 1 + + @property + def phong(self): + return self._vavle_material.get_int('$phong', 0) == 1 + + @property + def selfillum(self): + return self._vavle_material.get_int('$selfillum', 0) == 1 + + @property + def basealphaenvmapmask(self): + return self._vavle_material.get_int('$basealphaenvmapmask', 1) == 1 + + @property + def normalmapalphaenvmapmask(self): + return self._vavle_material.get_int('$normalmapalphaenvmapmask', 0) == 1 + + @property + def envmap(self): + return self._vavle_material.get_string('$envmap', None) is not None + + @property + def envmapmask(self): + texture_path = self._vavle_material.get_param('$envmapmask', None) + if texture_path is not None: + image = self.load_texture_or_default(texture_path, (1, 1, 1, 1.0)) + image.colorspace_settings.is_data = True + image.colorspace_settings.name = 'Non-Color' + return image + return None + + @property + def envmaptint(self): + color_value, value_type = self._vavle_material.get_vector('$envmaptint', [1, 1, 1]) + divider = 255 if value_type is int else 1 + color_value = list(map(lambda a: a / divider, color_value)) + if len(color_value) == 1: + color_value = [color_value[0], color_value[0], color_value[0]] + + return self.ensure_length(color_value, 4, 1.0) def create_nodes(self, material_name): if super().create_nodes(material_name) in ['UNKNOWN', 'LOADED']: @@ -57,29 +129,101 @@ def create_nodes(self, material_name): self.bpy_material.shadow_method = 'NONE' self.bpy_material.use_backface_culling = True material_output = self.create_node(Nodes.ShaderNodeOutputMaterial) - shader = self.create_node(Nodes.ShaderNodeBsdfPrincipled, self.SHADER) - self.connect_nodes(shader.outputs['BSDF'], material_output.inputs['Surface']) - - basetexture = self.basetexture - - if basetexture: - basetexture_node = self.create_and_connect_texture_node(basetexture, - shader.inputs['Base Color'], - name='$basetexture') - if self.alphatest: - self.bpy_material.blend_method = 'HASHED' - self.bpy_material.shadow_method = 'HASHED' - self.connect_nodes(basetexture_node.outputs['Alpha'], shader.inputs['Alpha']) + if self.alphatest or self.translucent: if self.translucent: self.bpy_material.blend_method = 'BLEND' - self.bpy_material.shadow_method = 'HASHED' - self.bpy_material.use_backface_culling = True - self.bpy_material.show_transparent_back = False - self.connect_nodes(basetexture_node.outputs['Alpha'], shader.inputs['Alpha']) - - if not self.phong: - shader.inputs['Specular'].default_value = 0 + else: + self.bpy_material.blend_method = 'HASHED' + self.bpy_material.shadow_method = 'HASHED' + + if self.use_bvlg_status: + if self.phong: + #please use VertexLitGeneric instead + pass + + self.do_arrange = False + group_node = self.create_node_group("LightMappedGeneric", [-200, 0]) + parentnode = material_output + if self.alphatest or self.translucent: + alphatest_node = self.create_node_group("$alphatest", [250, 0]) + parentnode = alphatest_node + material_output.location = [450, 0] + alphatest_node.inputs['$alphatestreference [value]'].default_value = self.alphatestreference + alphatest_node.inputs['$allowalphatocoverage [boolean]'].default_value = self.allowalphatocoverage + self.connect_nodes(alphatest_node.outputs['BSDF'], material_output.inputs['Surface']) + + self.connect_nodes(group_node.outputs['BSDF'], parentnode.inputs[0]) + if self.basetexture: + basetexture_node = self.create_and_connect_texture_node(self.basetexture, + group_node.inputs['$basetexture [texture]'], + name='$basetexture') + basetexture_node.location = [-800, 0] + if self.basetexturetransform: + UV, self.UVmap = self.handle_transform(self.basetexturetransform, basetexture_node.inputs[0]) + else: + UV = None + albedo = basetexture_node.outputs['Color'] + if self.basealphaenvmapmask: + self.connect_nodes(basetexture_node.outputs['Alpha'], + group_node.inputs['envmapmask [basemap texture alpha]']) + if self.alphatest: + self.connect_nodes(basetexture_node.outputs['Alpha'], + alphatest_node.inputs['Alpha [basemap texture alpha]']) + + if self.detail: + albedo, detail = self.handle_detail(group_node.inputs['$basetexture [texture]'], albedo, UV=UV) + + if self.color: + group_node.inputs['$color [RGB field]'].default_value = self.color or self.color2 + + if self.envmap: + group_node.inputs['$envmap [boolean]'].default_value = 1 + if self.envmaptint: + group_node.inputs['$envmaptint [RGB field]'].default_value = self.envmaptint + + if self.bumpmap: + bumpmap_node = self.create_and_connect_texture_node(self.bumpmap, + group_node.inputs['$bumpmap [texture]'], + name='$bumpmap', + UV=UV) + if self.bumptransform: + self.handle_transform(self.bumptransform, bumpmap_node.inputs[0]) + bumpmap_node.location = [-800, -220] + if self.normalmapalphaenvmapmask: + self.connect_nodes(bumpmap_node.outputs['Alpha'], + group_node.inputs['envmapmask [basemap texture alpha]']) + + if self.selfillum: + group_node.inputs['$selfillum [bool]'].default_value = 1 + if self.selfillummask: + selfillummask_node = self.create_and_connect_texture_node(self.selfillummask, group_node.inputs[ + '$selfillummask [texture alpha]'], UV=UV) + selfillummask_node.location = [-500, -510] + elif self.basetexture is not None: + self.connect_nodes(basetexture_node.outputs['Alpha'], + group_node.inputs['$selfillummask [texture alpha]']) + else: + shader = self.create_node(Nodes.ShaderNodeBsdfPrincipled, self.SHADER) + self.connect_nodes(shader.outputs['BSDF'], material_output.inputs['Surface']) + + basetexture = self.basetexture + if basetexture: + basetexture_node = self.create_and_connect_texture_node(basetexture, + shader.inputs['Base Color'], + name='$basetexture') + if self.envmap: + self.connect_nodes(basetexture_node.outputs['Alpha'], shader.inputs['Specular']) + shader.inputs['Roughness'].default_value = 0.2 + if self.alphatest: + self.connect_nodes(basetexture_node.outputs['Alpha'], shader.inputs['Alpha']) + if self.translucent: + self.bpy_material.use_backface_culling = True + self.bpy_material.show_transparent_back = False + self.connect_nodes(basetexture_node.outputs['Alpha'], shader.inputs['Alpha']) + + if not self.phong: + shader.inputs['Specular'].default_value = 0 class ReflectiveLightmapGeneric(LightmapGeneric): diff --git a/bpy_utilities/material_loader/shaders/source1_shaders/lightmapped_4wayblend.py b/bpy_utilities/material_loader/shaders/source1_shaders/lightmapped_4wayblend.py index 2649507f..9e48496d 100644 --- a/bpy_utilities/material_loader/shaders/source1_shaders/lightmapped_4wayblend.py +++ b/bpy_utilities/material_loader/shaders/source1_shaders/lightmapped_4wayblend.py @@ -1,9 +1,10 @@ +from .detail import DetailSupportMixin from ...shader_base import Nodes from ..source1_shader_base import Source1ShaderBase import bpy -class Lightmapped4WayBlend(Source1ShaderBase): +class Lightmapped4WayBlend(DetailSupportMixin): SHADER = 'lightmapped_4wayblend' @property @@ -75,12 +76,47 @@ def bumpmap4(self): return image return None + def lumstart(self, N = 1): + return self._vavle_material.get_float(f"$texture{N}_lumstart", 0) + + def lumend(self, N = 1): + return self._vavle_material.get_float(f"$texture{N}_lumend", 1) + + def lumblendfactor(self, N = 1): + return self._vavle_material.get_float(f"$lumblendfactor{N}", 0) + + def blendstart(self, N = 1): + return self._vavle_material.get_float(f"$texture{N}_blendstart", 0) + + def blendend(self, N = 1): + return self._vavle_material.get_float(f"$texture{N}_blendend", 1) + + def getblends(self): + keyvalues = {} + keyvalues['$texture1_lumstart'] = self.lumstart(1) + keyvalues['$texture1_lumend'] = self.lumend(1) + for i in range(2, 5): + keyvalues[f'$texture{i}_lumstart' ] = self.lumstart(i) + keyvalues[f'$texture{i}_lumend'] = self.lumend(i) + keyvalues[f'$lumblendfactor{i}'] = self.lumblendfactor(i) + keyvalues[f'$texture{i}_blendstart'] = self.blendstart(i) + keyvalues[f'$texture{i}_blendend'] = self.blendend(i) + return keyvalues + + def putblends(self, blends : dict, group : Nodes.ShaderNodeGroup): + for key, value in blends.items(): + group.inputs[key].default_value = value + + def create_nodes(self, material_name): if super().create_nodes(material_name) in ['UNKNOWN', 'LOADED']: return material_output = self.create_node(Nodes.ShaderNodeOutputMaterial) - shader = self.create_node(Nodes.ShaderNodeBsdfPrincipled, self.SHADER) + if (self.use_bvlg): + shader = self.create_node_group("LightMappedGeneric", name="LightMappedGeneric") + else: + shader = self.create_node(Nodes.ShaderNodeBsdfPrincipled, self.SHADER) self.connect_nodes(shader.outputs['BSDF'], material_output.inputs['Surface']) basetexture1 = self.basetexture @@ -127,9 +163,34 @@ def create_nodes(self, material_name): bumpmap_node.image = normal_texture4 normals[3] = bumpmap_node - vertex_color = self.create_node(Nodes.ShaderNodeVertexColor) - vertex_color.layer_name = 'multiblend' + vertex_color = self.create_node(Nodes.ShaderNodeVertexColor) + vertex_color.layer_name = 'multiblend' + if (self.use_bvlg): + blend = self.create_node_group("4wayBlend", name="4wayBlend") + + self.connect_nodes(vertex_color.outputs['Color'], blend.inputs['Vertex Color']) + + if bases[0]: + self.connect_nodes(bases[0].outputs['Color'], blend.inputs['$basetexture']) + if normals[0]: + self.connect_nodes(normals[0].outputs['Color'], blend.inputs['$bumpmap']) + for i in range(1, 4): + if bases[i]: + self.connect_nodes(bases[i].outputs['Color'], blend.inputs[f'$basetexture{i+1}']) + if normals[i]: + self.connect_nodes(normals[i].outputs['Color'], blend.inputs[f'$bumpmap{i+1}']) + + self.connect_nodes(blend.outputs['$bumpmap [texture]'], shader.inputs['$bumpmap [texture]']) + if self.detail: + self.handle_detail(shader.inputs['$basetexture [texture]'], blend.outputs['$basetexture [texture]']) + else: + self.connect_nodes(blend.outputs['$basetexture [texture]'], shader.inputs['$basetexture [texture]']) + self.connect_nodes(blend.outputs['$bumpmap [texture]'], shader.inputs['$bumpmap [texture]']) + self.putblends(self.getblends(), blend) + + + else: color_mixer = self.create_node(Nodes.ShaderNodeGroup) color_mixer.node_tree = self.get_or_create_4way_mix_group() normal_mixer = self.create_node(Nodes.ShaderNodeGroup) @@ -164,6 +225,7 @@ def create_nodes(self, material_name): self.connect_nodes(normalmap_node.outputs['Normal'], shader.inputs['Normal']) self.connect_nodes(color_mixer.outputs['Color'], shader.inputs['Base Color']) + def get_or_create_4way_mix_group(self): mixer_group = bpy.data.node_groups.get("4way_mixer", None) if mixer_group is None: diff --git a/bpy_utilities/material_loader/shaders/source1_shaders/vertexlit_generic.py b/bpy_utilities/material_loader/shaders/source1_shaders/vertexlit_generic.py index fa8d9ce8..70c9f110 100644 --- a/bpy_utilities/material_loader/shaders/source1_shaders/vertexlit_generic.py +++ b/bpy_utilities/material_loader/shaders/source1_shaders/vertexlit_generic.py @@ -19,6 +19,10 @@ def bumpmap(self): return image return None + @property + def bumptransform(self): + return self._vavle_material.get_transform_matrix('$bumptransform', {'center': (0.5, 0.5, 0), 'scale': (1.0, 1.0, 1), 'rotate': (0, 0, 0), 'translate': (0, 0, 0)}) + @property def basetexture(self): texture_path = self._vavle_material.get_param('$basetexture', None) @@ -251,6 +255,8 @@ def create_nodes(self, material_name): name='$bumpmap', UV=UV) bumpmap_node.location = [-800, -220] + if self.bumptransform: + self.handle_transform(self.bumptransform, bumpmap_node.inputs[0]) if self.normalmapalphaenvmapmask: self.connect_nodes(bumpmap_node.outputs['Alpha'], group_node.inputs['envmapmask [basemap texture alpha]'])