forked from phenom/healer-man
Release Healer Man 0.1.24
This commit is contained in:
1 parent
c4346751a9
commit
bac0da9300
118 files changed
+857
-289
No files matched your search
@@ -6,6 +6,7 @@ Expected invocation:
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from array import array
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
@@ -111,6 +112,69 @@ def material_image_key(material: bpy.types.Material) -> str:
|
||||
return f"material:{material.name.casefold()}"
|
||||
|
||||
|
||||
def material_image(material: bpy.types.Material) -> bpy.types.Image | None:
|
||||
if not material.use_nodes or material.node_tree is None:
|
||||
return None
|
||||
for node in material.node_tree.nodes:
|
||||
if node.type == "TEX_IMAGE" and node.image is not None:
|
||||
return node.image
|
||||
return None
|
||||
|
||||
|
||||
def image_alpha_role(image: bpy.types.Image | None) -> str:
|
||||
"""Classify source alpha without turning fully opaque RGBA textures translucent."""
|
||||
if image is None or image.channels < 4:
|
||||
return "opaque"
|
||||
pixels = array("f", [0.0]) * len(image.pixels)
|
||||
image.pixels.foreach_get(pixels)
|
||||
alpha_values = pixels[3::image.channels]
|
||||
if min(alpha_values, default=1.0) >= 0.999:
|
||||
return "opaque"
|
||||
if any(0.001 < alpha < 0.999 for alpha in alpha_values):
|
||||
return "blend"
|
||||
return "cutout"
|
||||
|
||||
|
||||
def preserve_material_alpha(material: bpy.types.Material) -> str:
|
||||
image = material_image(material)
|
||||
role = image_alpha_role(image)
|
||||
if role == "opaque" or material.node_tree is None:
|
||||
return role
|
||||
|
||||
image_node = next(
|
||||
node
|
||||
for node in material.node_tree.nodes
|
||||
if node.type == "TEX_IMAGE" and node.image == image
|
||||
)
|
||||
principled = next(
|
||||
(node for node in material.node_tree.nodes if node.type == "BSDF_PRINCIPLED"),
|
||||
None,
|
||||
)
|
||||
if principled is None:
|
||||
return role
|
||||
alpha_output = image_node.outputs.get("Alpha")
|
||||
alpha_input = principled.inputs.get("Alpha")
|
||||
if alpha_output is None or alpha_input is None:
|
||||
return role
|
||||
|
||||
if role == "blend":
|
||||
if not alpha_input.is_linked:
|
||||
material.node_tree.links.new(alpha_output, alpha_input)
|
||||
material.blend_method = "BLEND"
|
||||
if hasattr(material, "surface_render_method"):
|
||||
material.surface_render_method = "BLENDED"
|
||||
else:
|
||||
alpha_clip = material.node_tree.nodes.new("ShaderNodeMath")
|
||||
alpha_clip.name = "RuneWaker Alpha Clip"
|
||||
alpha_clip.operation = "GREATER_THAN"
|
||||
alpha_clip.inputs[1].default_value = 0.5
|
||||
material.node_tree.links.new(alpha_output, alpha_clip.inputs[0])
|
||||
material.node_tree.links.new(alpha_clip.outputs[0], alpha_input)
|
||||
material.blend_method = "CLIP"
|
||||
material.alpha_threshold = 0.5
|
||||
return role
|
||||
|
||||
|
||||
def deduplicate_materials(objects: list[bpy.types.Object]) -> dict[str, int]:
|
||||
canonical: dict[str, bpy.types.Material] = {}
|
||||
replacements = 0
|
||||
@@ -126,7 +190,7 @@ def deduplicate_materials(objects: list[bpy.types.Object]) -> dict[str, int]:
|
||||
replacements += 1
|
||||
else:
|
||||
canonical[key] = material
|
||||
material["semanticRole"] = "opaque"
|
||||
material["semanticRole"] = preserve_material_alpha(material)
|
||||
material["sourceFormat"] = "RuneWaker DDS"
|
||||
return {"unique": len(canonical), "replacements": replacements}
|
||||
|
||||
|
||||
Reference in new issue
Block a user