diff --git a/infinigen/assets/materials/water.py b/infinigen/assets/materials/water.py index bc16177e..edcc133c 100644 --- a/infinigen/assets/materials/water.py +++ b/infinigen/assets/materials/water.py @@ -5,6 +5,8 @@ # Acknowledgment: This file draws inspiration from https://www.youtube.com/watch?v=X3LlsdddMLo by Kev Binge +import logging + import bpy import gin import numpy as np @@ -23,6 +25,7 @@ mod_name = "geo_water" name = "water" info = {} +logger = logging.getLogger(__name__) @gin.configurable("geo") @@ -237,11 +240,13 @@ def shader( asset_paths, coastal, color=("color_category", "water"), + scatter_color=("color_category", "water_scatter"), enable_scatter=True, colored=False, emissive_foam=False, volume_density=("uniform", 0.07, 0.09), anisotropy=("clip_gaussian", 0.75, 0.2, 0.5, 1), + scatter_density=("uniform", 0.0005, 0.002), mix_surface=False, random_seed=0, ): @@ -250,6 +255,7 @@ def shader( # Code generated using version 2.3.1 of the node_transpiler (partly) with FixedSeed(random_seed): color = rg(color) + scatter_color = rg(scatter_color) light_path = nw.new_node(Nodes.LightPath) if colored: @@ -332,15 +338,33 @@ def shader( rgb = nw.new_node(Nodes.RGB) rgb.outputs[0].default_value = color - principled_volume = nw.new_node( - Nodes.PrincipledVolume, + + volume_density = rg(volume_density) + volume_absorption = nw.new_node( + Nodes.VolumeAbsorption, input_kwargs={ "Color": rgb, - "Absorption Color": rgb, - "Density": rg(volume_density) if enable_scatter else 0, - "Anisotropy": rg(anisotropy), + "Density": volume_density, }, ) + logger.debug(f"Water Volume Absorption: color {color}, density: {volume_density}") + + scatter_rgb = nw.new_node(Nodes.RGB) + scatter_density = rg(scatter_density) if enable_scatter else 0 + scatter_anisotropy = rg(anisotropy) + scatter_rgb.outputs[0].default_value = scatter_color + volume_scatter = nw.new_node( + Nodes.VolumeScatter, + input_kwargs={ + "Color": scatter_rgb, + "Density": scatter_density, + "Anisotropy": scatter_anisotropy, + }, + ) + logger.debug(f"Water Volume Scattering: color {scatter_color}, density: {scatter_density}, anistropy: {scatter_anisotropy}") + #volume_scatter.phase = "FOURNIER_FORAND" # for Blender 4.3 + + principled_volume = nw.new_node(Nodes.AddShader, [volume_absorption, volume_scatter]) material_output = nw.new_node( Nodes.MaterialOutput, diff --git a/infinigen/core/nodes/node_info.py b/infinigen/core/nodes/node_info.py index 8144a0b4..15aa3d62 100644 --- a/infinigen/core/nodes/node_info.py +++ b/infinigen/core/nodes/node_info.py @@ -224,11 +224,14 @@ class Nodes: # Shaders MixShader = "ShaderNodeMixShader" + AddShader = "ShaderNodeAddShader" DiffuseBSDF = "ShaderNodeBsdfDiffuse" PrincipledBSDF = "ShaderNodeBsdfPrincipled" TranslucentBSDF = "ShaderNodeBsdfTranslucent" TransparentBSDF = "ShaderNodeBsdfTransparent" PrincipledVolume = "ShaderNodeVolumePrincipled" + VolumeAbsorption = "ShaderNodeVolumeAbsorption" + VolumeScatter = "ShaderNodeVolumeScatter" PrincipledHairBSDF = "ShaderNodeBsdfHairPrincipled" Emission = "ShaderNodeEmission" Fresnel = "ShaderNodeFresnel" diff --git a/infinigen/core/rendering/render.py b/infinigen/core/rendering/render.py index 43cc44d8..62e7789d 100644 --- a/infinigen/core/rendering/render.py +++ b/infinigen/core/rendering/render.py @@ -12,11 +12,13 @@ import os import time from pathlib import Path +import shutil import bpy import gin import numpy as np from imageio import imwrite +import cv2 from infinigen.core import init, surface from infinigen.core.nodes.node_wrangler import Nodes, NodeWrangler @@ -225,25 +227,56 @@ def configure_compositor_output( def shader_random(nw: NodeWrangler): - # Code generated using version 2.4.3 of the node_transpiler + # Code generated using version 2.6.5 of the node_transpiler + object_info_1 = nw.new_node(Nodes.ObjectInfo_Shader) - object_info = nw.new_node(Nodes.ObjectInfo_Shader) + value = nw.new_node(Nodes.Value) + value.outputs[0].default_value = 10 - white_noise_texture = nw.new_node( - Nodes.WhiteNoiseTexture, input_kwargs={"Vector": object_info.outputs["Random"]} - ) + divide = nw.new_node(Nodes.Math, input_kwargs={0: 1.0000, 1: value}, attrs={'operation': 'DIVIDE'}) + + divide_1 = nw.new_node(Nodes.Math, input_kwargs={0: object_info_1.outputs["Random"], 1: divide}, + attrs={'operation': 'DIVIDE'}) + + floor = nw.new_node(Nodes.Math, input_kwargs={0: divide_1}, attrs={'operation': 'FLOOR'}) + + multiply = nw.new_node(Nodes.Math, input_kwargs={0: floor, 1: divide}, attrs={'operation': 'MULTIPLY'}) + + divide_2 = nw.new_node(Nodes.Math, input_kwargs={0: object_info_1.outputs["Random"], 1: divide}, + attrs={'operation': 'DIVIDE'}) + + fract = nw.new_node(Nodes.Math, input_kwargs={0: divide_2}, attrs={'operation': 'FRACT'}) + + divide_3 = nw.new_node(Nodes.Math, input_kwargs={0: fract, 1: divide}, attrs={'operation': 'DIVIDE'}) + + floor_1 = nw.new_node(Nodes.Math, input_kwargs={0: divide_3}, attrs={'operation': 'FLOOR'}) + + multiply_1 = nw.new_node(Nodes.Math, input_kwargs={0: floor_1, 1: divide}, attrs={'operation': 'MULTIPLY'}) + + divide_4 = nw.new_node(Nodes.Math, input_kwargs={0: divide_2, 1: divide}, attrs={'operation': 'DIVIDE'}) + + fract_1 = nw.new_node(Nodes.Math, input_kwargs={0: divide_4}, attrs={'operation': 'FRACT'}) + + divide_5 = nw.new_node(Nodes.Math, input_kwargs={0: fract_1, 1: divide}, attrs={'operation': 'DIVIDE'}) + + floor_2 = nw.new_node(Nodes.Math, input_kwargs={0: divide_5}, attrs={'operation': 'FLOOR'}) + + multiply_2 = nw.new_node(Nodes.Math, input_kwargs={0: floor_2, 1: divide}, attrs={'operation': 'MULTIPLY'}) + + combine_color = nw.new_node(Nodes.CombineColor, + input_kwargs={'Red': multiply, 'Green': multiply_1, 'Blue': multiply_2}) + + emission = nw.new_node( + "ShaderNodeEmission", input_kwargs={"Color": combine_color, "Strength": 0.5}) + _ = nw.new_node(Nodes.MaterialOutput, input_kwargs={'Surface': emission}) - nw.new_node( - Nodes.MaterialOutput, - input_kwargs={"Surface": white_noise_texture.outputs["Color"]}, - ) def global_flat_shading(): for obj in bpy.context.scene.view_layers["ViewLayer"].objects: if "fire_system_type" in obj and obj["fire_system_type"] == "volume": continue - if obj.name.lower() in {"atmosphere", "atmosphere_fine"}: + if obj.name.lower() in {"atmosphere", "atmosphere_fine", "liquid", "liquid_fine"}: bpy.data.objects.remove(obj) elif obj.active_material is not None: nw = obj.active_material.node_tree @@ -252,6 +285,7 @@ def global_flat_shading(): vol_socket = node.inputs["Volume"] if len(vol_socket.links) > 0: nw.links.remove(vol_socket.links[0]) + bpy.context.view_layer.update() for obj in bpy.context.scene.view_layers["ViewLayer"].objects: if obj.type != "MESH": @@ -278,7 +312,7 @@ def global_flat_shading(): nw.links.remove(link) -def postprocess_blendergt_outputs(frames_folder, output_stem): +def postprocess_blendergt_outputs(frames_folder, output_stem, frame, tmp_dir): # Save flow visualization flow_dst_path = frames_folder / f"Vector{output_stem}.exr" flow_array = load_flow(flow_dst_path) @@ -325,15 +359,11 @@ def postprocess_blendergt_outputs(frames_folder, output_stem): # Save unique instances visualization uniq_inst_path = frames_folder / f"UniqueInstances{output_stem}.exr" - uniq_inst_array = load_uniq_inst(uniq_inst_path) - np.save( - flow_dst_path.with_name(f"InstanceSegmentation{output_stem}.npy"), - uniq_inst_array, - ) - imwrite( - uniq_inst_path.with_name(f"InstanceSegmentation{output_stem}.png"), - colorize_int_array(uniq_inst_array), - ) + #uniq_inst_array = load_uniq_inst(uniq_inst_path) + uniq_inst_tmp_path = f"{tmp_dir}/{frame:04d}.png" + uniq_inst_array = cv2.imread(uniq_inst_tmp_path) + np.save(flow_dst_path.with_name(f"InstanceSegmentation{output_stem}.npy"), uniq_inst_array) + shutil.copy(uniq_inst_tmp_path, str(flow_dst_path.with_name(f"InstanceSegmentation{output_stem}.png"))) uniq_inst_path.unlink() @@ -475,7 +505,7 @@ def render_image( if flat_shading: bpy.context.scene.frame_set(frame) suffix = get_suffix(dict(frame=frame, **indices)) - postprocess_blendergt_outputs(frames_folder, suffix) + postprocess_blendergt_outputs(frames_folder, suffix, frame, tmp_dir) else: cam_util.save_camera_parameters( camera, diff --git a/infinigen/core/util/color.py b/infinigen/core/util/color.py index 8801e379..d0667841 100644 --- a/infinigen/core/util/color.py +++ b/infinigen/core/util/color.py @@ -58,7 +58,16 @@ def N(m, std, **kwargs): "water": (U(0.2, 0.6), N(0.5, 0.1), U(0.7, 1)), "darker_water": (U(0.2, 0.6), N(0.5, 0.1), U(0.2, 0.3)), "under_water": (U(0.5, 0.7), U(0.7, 0.95), U(0.7, 1)), - "eye_schlera": (U(0.05, 0.15), U(0.2, 0.8), U(0.05, 0.5)), + "water_scatter": ( + N(0.474, 0.05), + N(0.8, 0.1), + N(0.9, 0.1) + ), + "seawater": ( + N(0.453, 0.03), + N(0.95, 0.05), + N(0.5, 0.1) + ), "eye_schlera": (U(0.05, 0.15), U(0.2, 0.8), U(0.05, 0.5)), "eye_pupil": (U(0, 1), U(0.1, 0.9), U(0.1, 0.9)), "beak": (U(0, 0.13), U(0, 0.9), U(0.1, 0.6)), "fur": (U(0, 0.11), U(0.5, 0.95), U(0.02, 0.9)), diff --git a/infinigen_examples/configs_nature/scene_types/coral_reef.gin b/infinigen_examples/configs_nature/scene_types/coral_reef.gin index 12917127..6dc31a6b 100644 --- a/infinigen_examples/configs_nature/scene_types/coral_reef.gin +++ b/infinigen_examples/configs_nature/scene_types/coral_reef.gin @@ -1,11 +1,13 @@ include 'infinigen_examples/configs_nature/scene_types/under_water.gin' -compose_nature.kelp_chance = 0.1 -compose_nature.urchin_chance = 0.1 +compose_nature.kelp_chance = 0.0 +compose_nature.urchin_chance = 0.0 compose_nature.corals_chance = 1. -compose_nature.seaweed_chance = 0.2 -compose_nature.seashell_chance = 0.7 +compose_nature.seaweed_chance = 0.0 +compose_nature.seashell_chance = 0.0 compose_nature.jellyfish_chance = 0.0 -water.geo.with_waves=True \ No newline at end of file +water.geo.with_waves=True + +water.shader.color = ("color_category", "under_water") \ No newline at end of file