content/hifi-content/caitlyn/scratch/hifi_tools (5)/world/material.py
2022-02-13 22:19:19 +01:00

372 lines
No EOL
12 KiB
Python

# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
# Material Helper UI
# By Matti 'Menithal' Lahtinen
import bpy
from bpy.props import (
StringProperty,
BoolProperty,
FloatVectorProperty,
FloatProperty
)
def update_color(self, context):
mat = context.material
mat.diffuse_color = mat.hifi_material_color
def update_roughness(self, context):
mat = context.material
# Hifi values are inverse as Blender Hardness actually defines Glossiness.
mat.specular_hardness = int((1-(mat.hifi_roughness_float / 100))*512)
def update_metallicness(self, context):
mat = context.material
per = mat.hifi_metallic_float/100
mat.specular_color = (per, per, per)
def update_transparency(self, context):
mat = context.material
mat.alpha = 1 - mat.hifi_transparency_float/100
if mat.alpha < 1:
mat.use_transparency = True
mat.transparency_method = 'Z_TRANSPARENCY'
else:
mat.use_transparency = False
# Helper functions to make code a bit more readable, and using less large functions that do the same thing
def that_has_diffuse (texture_slot): return texture_slot.use_map_color_diffuse
def that_has_transparency ( texture_slot): return texture_slot.use_map_alpha
def that_has_emit ( texture_slot): return texture_slot.use_map_emit
def that_has_metallicness (texture_slot): return texture_slot.use_map_color_spec
def that_has_glossiness ( texture_slot): return texture_slot.use_map_hardness
def that_has_normal (texture_slot): return texture_slot.use_map_normal
# Various operations used as short hands
def texture_operation_diffuse( slot, mode, texture):
slot.use_map_color_diffuse = mode
def texture_operation_glossiness( slot, mode, texture ):
slot.use_map_hardness = mode
def texture_operation_metallic( slot, mode, texture ):
slot.use_map_color_spec = mode
def texture_operation_normal (slot, mode, texture ):
slot.use_map_normal = mode
texture.use_normal_map = mode
def texture_operation_transparency( slot, mode, texture):
slot.use_map_alpha = mode
def texture_operation_emit( slot, mode,texture):
slot.use_map_emit = mode
# find first texture in material that has *
# Takes a material context, and uses has_operation function to search for something
def find_first_texture_in(has_operation):
current_textures = bpy.context.active_object.active_material.texture_slots
found_slot = None
for texture_slot in current_textures:
if texture_slot is not None:
result = has_operation(texture_slot)
if result:
found_slot = texture_slot
break
return found_slot
class HifiMaterialOperator(bpy.types.Panel):
bl_idname = "material_helper.hifi"
bl_label = "High Fidelity Material Helper"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "material"
COMPAT_ENGINES = {'BLENDER_RENDER'}
bpy.types.Material.hifi_material_color = FloatVectorProperty(
name = "Tint",
description = "Set Material Tint",
default = (0.8, 0.8, 0.8),
min = 0.0,
max = 1.0,
subtype = "COLOR",
update = update_color
)
bpy.types.Material.hifi_roughness_float = FloatProperty(
name = "Roughness",
description = "Set Roughness",
default = 30,
min = 0.0,
max = 100,
subtype = "PERCENTAGE",
update = update_roughness
)
bpy.types.Material.hifi_metallic_float = FloatProperty(
name = "Metallicness",
description = "Set Metallicness",
default = 0.0,
min = 0.0,
max = 100,
subtype = "PERCENTAGE",
update = update_metallicness
)
bpy.types.Material.hifi_transparency_float = FloatProperty(
name = "Transparency",
description = "Set Transparency",
default = 0.0,
min = 0.0,
max = 100,
subtype = "PERCENTAGE",
update = update_transparency
)
@classmethod
def poll(self, context):
mat = context.material
engine = context.scene.render.engine
return mat and engine in self.COMPAT_ENGINES
def draw (self, context):
layout = self.layout
row = layout.row()
row.prop(context.material, "hifi_material_color")
row.operator(HifiResetDiffuseOperator.bl_idname)
build_texture_ui(context, layout, HifiDiffuseTextureOperator)
build_texture_ui(context, layout, HifiRoughnessTextureOperator, "hifi_roughness_float")
layout.label(text='Note, Glossiness is inverse of Roughness')
layout.separator()
build_texture_ui(context, layout, HifiMetallicTextureOperator, "hifi_metallic_float")
build_texture_ui(context, layout, HifiNormalTextureOperator)
build_texture_ui(context, layout, HifiTransparencyTextureOperator, "hifi_transparency_float")
build_texture_ui(context, layout, HifiEmitTextureOperator)
# setattr(mat, "hifi_material_color", mat.diffuse_color)
# mat.specular_hardness = int((1-(mat.hifi_roughness_float / 100))*512)
# setattr(mat, "hifi_roughness_float", (1 - mat.specular_hardness / 512) * 100)
# setattr(mat, "hifi_metallic_float", mat.specular_color[0] * 100)
# setattr(mat, "hifi_transparency_float")
def build_texture_ui(context, layout, operator, float_widget = None):
material = context.material
texture_slot = find_first_texture_in(lambda slot: operator.has_operation(None, slot))
if texture_slot and texture_slot.texture.type != 'NONE':
layout.label(text = operator.bl_label)
split = layout.split(0.9)
box = split.box()
# TODO: allow previews, but tried it and was having issues:
#box.template_preview(texture_slot.texture,
# parent=material, slot=texture_slot,
# preview_id=operator.bl_label+'preview')
box.template_image(texture_slot.texture, "image", texture_slot.texture.image_user)
button = split.operator(operator.bl_idname, icon='X', text="")
button.enabled = False
else:
row = layout.row()
if float_widget:
row.prop(material, float_widget)
button = row.operator(operator.bl_idname, icon='ZOOMIN')
button.enabled = True
layout.separator()
class HifiResetDiffuseOperator(bpy.types.Operator):
bl_idname = HifiMaterialOperator.bl_idname + "_diffuse_reset_color"
bl_label = "Reset Tint"
def execute(self, context):
mat = context.material
mat.hifi_material_color = (1,1,1)
mat.diffuse_color = (1,1,1)
layout = self.layout
return {'FINISHED'}
class HifiGenericTextureOperator(bpy.types.Operator):
has_operation = None
texture_operation = None
postfix = ""
enabled = True
def execute(self, context):
if self.texture_operation is not None and self.has_operation is not None:
found_slot = find_first_texture_in(self.has_operation)
print("Found Slot", found_slot, self.enabled)
if self.enabled and found_slot is None:
material = bpy.context.active_object.active_material
slots = material.texture_slots
name = material.name + "_" + self.postfix
texture = bpy.data.textures.new(name, 'IMAGE')
slot = slots.add()
slot.use_map_color_diffuse = False
self.texture_operation(slot, True, texture)
slot.texture = texture
elif not self.enabled and found_slot:
self.texture_operation(found_slot, False, None)
found_slot.use = False
return {'FINISHED'}
class HifiDiffuseTextureOperator(HifiGenericTextureOperator, bpy.types.Operator):
bl_idname = HifiMaterialOperator.bl_idname + "_diffuse_texture"
bl_label = "Diffuse"
enabled = BoolProperty(name="enabled", default=True)
def has_operation(self, slot): return that_has_diffuse(slot)
def texture_operation(self, slot, mode, texture): texture_operation_diffuse(slot, mode, texture)
postfix = "diffuse"
class HifiRoughnessTextureOperator(HifiGenericTextureOperator, bpy.types.Operator):
bl_idname = HifiMaterialOperator.bl_idname + "_glossiness_texture"
bl_label = "Glossiness"
enabled = BoolProperty(name="enabled", default=True)
def has_operation(self, slot): return that_has_glossiness(slot)
def texture_operation(self, slot, mode, texture): texture_operation_glossiness(slot, mode, texture)
postfix = "glossiness"
class HifiMetallicTextureOperator(HifiGenericTextureOperator, bpy.types.Operator):
bl_idname = HifiMaterialOperator.bl_idname + "_metallic_texture"
bl_label = "Metallicness"
enabled = BoolProperty(name="enabled", default=True)
def has_operation(self, slot): return that_has_metallicness(slot)
def texture_operation(self, slot, mode, texture): texture_operation_metallic(slot, mode, texture)
postfix = "metallicness"
class HifiNormalTextureOperator(HifiGenericTextureOperator, bpy.types.Operator):
bl_idname = HifiMaterialOperator.bl_idname + "_normal_texture"
bl_label = "Normal"
enabled = BoolProperty(name="enabled", default=True)
def has_operation(self, slot): return that_has_normal(slot)
def texture_operation(self, slot, mode, texture): texture_operation_normal(slot, mode, texture)
postfix = "normal"
class HifiTransparencyTextureOperator(HifiGenericTextureOperator, bpy.types.Operator):
bl_idname = HifiMaterialOperator.bl_idname + "_transparency_texture"
bl_label = "Transparency"
enabled = BoolProperty(name="enabled", default=True)
def has_operation(self, slot): return that_has_transparency(slot)
def texture_operation(self, slot, mode, texture):
mat = bpy.context.active_object.active_material
if mode:
mat.use_transparency = True
mat.transparency_method = 'Z_TRANSPARENCY'
else:
mat.use_transparency = False
texture_operation_transparency(slot, mode, texture)
postfix = "transparency"
class HifiEmitTextureOperator(HifiGenericTextureOperator, bpy.types.Operator):
bl_idname = HifiMaterialOperator.bl_idname + "_emit_texture"
bl_label = "Emit"
enabled = BoolProperty(name="enabled", default=True)
def has_operation(self, slot): return that_has_emit(slot)
def texture_operation(self, slot, mode, texture): texture_operation_emit(slot, mode, texture)
postfix = "emit"
classes = [
HifiResetDiffuseOperator,
HifiDiffuseTextureOperator,
HifiRoughnessTextureOperator,
HifiMetallicTextureOperator,
HifiNormalTextureOperator,
HifiTransparencyTextureOperator,
HifiEmitTextureOperator,
HifiMaterialOperator
]
def register():
for cls in classes:
bpy.utils.register_class(cls)
def unregister():
for cls in classes:
bpy.utils.unregister_class(cls)
if __name__ == "__main__":
register()