feat: Add new Geometry Nodes groups for image relief and shadeless shader
- Implemented the "O Image Relief Plane" Geometry Nodes group to create a fixed-base image relief using depth images and various parameters. - Created the "O Shadeless" shader node group to display color without scene lighting while preserving shadows and reflections. - Introduced a preview feature for node groups, allowing for interactive visualization of node arrangements in an HTML format. - Added a template HTML file for rendering node previews with customizable views and controls.
This commit is contained in:
@@ -71,19 +71,22 @@ def _write_float_exr(rgba, output_path):
|
||||
return output_path
|
||||
|
||||
|
||||
def write_depth_texture(frame, output_path):
|
||||
"""Write a frame's camera-space XYZ and validity as float RGBA."""
|
||||
def write_depth_texture(frame, output_path, *, alpha):
|
||||
"""Write camera-space XYZ and alpha-weighted model validity as float RGBA."""
|
||||
import numpy as np
|
||||
|
||||
if frame.points is None:
|
||||
raise ValueError("Depth requires a point field")
|
||||
points = np.asarray(frame.points, dtype=np.float32)
|
||||
validity = np.asarray(frame.validity, dtype=np.float32)
|
||||
alpha = np.asarray(alpha, dtype=np.float32)
|
||||
if alpha.shape != validity.shape:
|
||||
raise ValueError("Depth Alpha must match the validity dimensions")
|
||||
if not np.isfinite(points).all():
|
||||
raise ValueError("Point field contains non-finite values")
|
||||
rgba = np.empty((*validity.shape, 4), dtype=np.float32)
|
||||
rgba[..., :3] = points
|
||||
rgba[..., 3] = validity
|
||||
rgba[..., 3] = alpha * validity
|
||||
return _write_float_exr(rgba, output_path)
|
||||
|
||||
|
||||
@@ -101,7 +104,7 @@ def write_depth_metadata(frame, reference_valid, output_path):
|
||||
raise ValueError("Depth metadata reference mask dimensions do not match")
|
||||
if intrinsics.shape != (3, 3):
|
||||
raise ValueError("Depth metadata requires 3x3 camera intrinsics")
|
||||
valid = (validity > 0.0) & np.isfinite(depth) & (depth > 0.0)
|
||||
valid = (validity > 0.5) & np.isfinite(depth) & (depth > 0.0)
|
||||
reference_valid &= valid
|
||||
if not valid.any():
|
||||
raise ValueError("Geometry frame contains no valid depth pixels")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Extend reliable Cutout depth along each visible component's silhouette."""
|
||||
"""Extend reliable depth along each visible component's silhouette."""
|
||||
|
||||
from dataclasses import replace
|
||||
|
||||
@@ -18,19 +18,20 @@ def extend_edge_depth(frame, alpha, alpha_threshold=0.9):
|
||||
return frame
|
||||
|
||||
visible = (alpha > 0.0) & (alpha >= alpha_threshold)
|
||||
opaque = visible & (alpha >= 0.95)
|
||||
candidates = (
|
||||
visible
|
||||
& (alpha >= 0.95)
|
||||
& (frame.validity > 0.0)
|
||||
opaque
|
||||
& (frame.validity > 0.5)
|
||||
& np.isfinite(depth)
|
||||
& (depth > 0.0)
|
||||
)
|
||||
if not candidates.any():
|
||||
return frame
|
||||
interior_distance = ndimage.distance_transform_edt(
|
||||
np.pad(candidates, 3, mode="edge")
|
||||
np.pad(opaque, 3, mode="edge")
|
||||
)[3:-3, 3:-3]
|
||||
core = candidates & (interior_distance > 2.0)
|
||||
interior = opaque & (interior_distance > 2.0)
|
||||
core = candidates & interior
|
||||
del interior_distance
|
||||
labels, _ = ndimage.label(visible, structure=np.ones((3, 3), dtype=bool))
|
||||
corrected = depth.copy()
|
||||
@@ -59,7 +60,7 @@ def extend_edge_depth(frame, alpha, alpha_threshold=0.9):
|
||||
& (distance <= 4.0)
|
||||
& (distance < background_distance[region])
|
||||
)
|
||||
target = (component & ~donors) | background
|
||||
target = (component & ~interior[region] & ~donors) | background
|
||||
corrected[region][target] = smoothed[target]
|
||||
background_distance[region][background] = distance[background]
|
||||
|
||||
|
||||
@@ -14,10 +14,8 @@ def _limited_model_input(source_path, output_path, max_input_size):
|
||||
from PIL import Image
|
||||
|
||||
with Image.open(source_path) as opened:
|
||||
limited = limit_image(opened.convert("RGBA"), max_input_size)
|
||||
background = Image.new("RGBA", limited.size, (0, 0, 0, 255))
|
||||
normalized = Image.alpha_composite(background, limited).convert("RGB")
|
||||
normalized.save(output_path, format="PNG", compress_level=1)
|
||||
limited = limit_image(opened.convert("RGB"), max_input_size)
|
||||
limited.save(output_path, format="PNG", compress_level=1)
|
||||
return output_path
|
||||
|
||||
|
||||
@@ -58,7 +56,6 @@ def generate_moge2_artifacts(
|
||||
*,
|
||||
generate_depth=False,
|
||||
normal_mode="NONE",
|
||||
correct_edge_depth=False,
|
||||
alpha_threshold=0.9,
|
||||
):
|
||||
"""Run MoGe-2 once and write only the requested file artifacts."""
|
||||
@@ -85,17 +82,13 @@ def generate_moge2_artifacts(
|
||||
if generate_depth:
|
||||
context.progress(0.45, "Generating depth texture")
|
||||
alpha = _image_alpha(input_path, frame.depth.shape)
|
||||
depth_frame = (
|
||||
extend_edge_depth(frame, alpha, alpha_threshold)
|
||||
if correct_edge_depth else frame
|
||||
)
|
||||
depth_frame = extend_edge_depth(frame, alpha, alpha_threshold)
|
||||
result["depth"] = write_depth_texture(
|
||||
depth_frame, context.directory / "depth.exr",
|
||||
depth_frame, context.directory / "depth.exr", alpha=alpha,
|
||||
)
|
||||
result["depth_metadata"] = write_depth_metadata(
|
||||
depth_frame,
|
||||
(alpha > 0.0) & (alpha >= alpha_threshold)
|
||||
if correct_edge_depth else alpha >= 0.1,
|
||||
(alpha > 0.0) & (alpha >= alpha_threshold),
|
||||
context.directory / "depth.json",
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user