Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Material Loader : add proper 4wayblend #114

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,6 @@ dmypy.json

# Pyre type checker
.pyre/

# Blender Project backups
*.blend1
Binary file modified assets/sycreation-s-default.blend
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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")
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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']:
Expand All @@ -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):
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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:
Expand Down
Loading