Spaces:
Running
on
Zero
Running
on
Zero
# Copyright (C) 2023, Princeton University. | |
# This source code is licensed under the BSD 3-Clause license found in the LICENSE file in the root directory of this source tree. | |
# Authors: Yiming Zuo | |
import bpy | |
from numpy.random import choice, normal, uniform | |
from infinigen.assets.material_assignments import AssetList | |
from infinigen.assets.objects.tables.legs.single_stand import ( | |
nodegroup_generate_single_stand, | |
) | |
from infinigen.assets.objects.tables.legs.square import nodegroup_generate_leg_square | |
from infinigen.assets.objects.tables.legs.straight import ( | |
nodegroup_generate_leg_straight, | |
) | |
from infinigen.assets.objects.tables.strechers import nodegroup_strecher | |
from infinigen.assets.objects.tables.table_top import nodegroup_generate_table_top | |
from infinigen.assets.objects.tables.table_utils import ( | |
nodegroup_create_anchors, | |
nodegroup_create_legs_and_strechers, | |
) | |
from infinigen.core import surface, tagging | |
from infinigen.core import tags as t | |
from infinigen.core.nodes import node_utils | |
# from infinigen.assets.materials import metal, metal_shader_list | |
# from infinigen.assets.materials.fabrics import fabric | |
from infinigen.core.nodes.node_wrangler import Nodes, NodeWrangler | |
from infinigen.core.placement.factory import AssetFactory | |
from infinigen.core.surface import NoApply | |
from infinigen.core.util.math import FixedSeed | |
def geometry_create_legs(nw: NodeWrangler, **kwargs): | |
createanchors = nw.new_node( | |
nodegroup_create_anchors().name, | |
input_kwargs={ | |
"Profile N-gon": kwargs["Leg Number"], | |
"Profile Width": kwargs["Leg Placement Top Relative Scale"] | |
* kwargs["Top Profile Width"], | |
"Profile Aspect Ratio": kwargs["Top Profile Aspect Ratio"], | |
}, | |
) | |
if kwargs["Leg Style"] == "single_stand": | |
leg = nw.new_node( | |
nodegroup_generate_single_stand(**kwargs).name, | |
input_kwargs={ | |
"Leg Height": kwargs["Leg Height"], | |
"Leg Diameter": kwargs["Leg Diameter"], | |
"Resolution": 64, | |
}, | |
) | |
leg = nw.new_node( | |
nodegroup_create_legs_and_strechers().name, | |
input_kwargs={ | |
"Anchors": createanchors, | |
"Keep Legs": True, | |
"Leg Instance": leg, | |
"Table Height": kwargs["Top Height"], | |
"Leg Bottom Relative Scale": kwargs[ | |
"Leg Placement Bottom Relative Scale" | |
], | |
"Align Leg X rot": True, | |
}, | |
) | |
elif kwargs["Leg Style"] == "straight": | |
leg = nw.new_node( | |
nodegroup_generate_leg_straight(**kwargs).name, | |
input_kwargs={ | |
"Leg Height": kwargs["Leg Height"], | |
"Leg Diameter": kwargs["Leg Diameter"], | |
"Resolution": 32, | |
"N-gon": kwargs["Leg NGon"], | |
"Fillet Ratio": 0.1, | |
}, | |
) | |
strecher = nw.new_node( | |
nodegroup_strecher().name, | |
input_kwargs={"Profile Width": kwargs["Leg Diameter"] * 0.5}, | |
) | |
leg = nw.new_node( | |
nodegroup_create_legs_and_strechers().name, | |
input_kwargs={ | |
"Anchors": createanchors, | |
"Keep Legs": True, | |
"Leg Instance": leg, | |
"Table Height": kwargs["Top Height"], | |
"Strecher Instance": strecher, | |
"Strecher Index Increment": kwargs["Strecher Increament"], | |
"Strecher Relative Position": kwargs["Strecher Relative Pos"], | |
"Leg Bottom Relative Scale": kwargs[ | |
"Leg Placement Bottom Relative Scale" | |
], | |
"Align Leg X rot": True, | |
}, | |
) | |
elif kwargs["Leg Style"] == "square": | |
leg = nw.new_node( | |
nodegroup_generate_leg_square(**kwargs).name, | |
input_kwargs={ | |
"Height": kwargs["Leg Height"], | |
"Width": 0.707 | |
* kwargs["Leg Placement Top Relative Scale"] | |
* kwargs["Top Profile Width"] | |
* kwargs["Top Profile Aspect Ratio"], | |
"Has Bottom Connector": (kwargs["Strecher Increament"] > 0), | |
"Profile Width": kwargs["Leg Diameter"], | |
}, | |
) | |
leg = nw.new_node( | |
nodegroup_create_legs_and_strechers().name, | |
input_kwargs={ | |
"Anchors": createanchors, | |
"Keep Legs": True, | |
"Leg Instance": leg, | |
"Table Height": kwargs["Top Height"], | |
"Leg Bottom Relative Scale": kwargs[ | |
"Leg Placement Bottom Relative Scale" | |
], | |
"Align Leg X rot": True, | |
}, | |
) | |
else: | |
raise NotImplementedError | |
leg = nw.new_node( | |
Nodes.SetMaterial, | |
input_kwargs={"Geometry": leg, "Material": kwargs["LegMaterial"]}, | |
) | |
group_output = nw.new_node( | |
Nodes.GroupOutput, | |
input_kwargs={"Geometry": leg}, | |
attrs={"is_active_output": True}, | |
) | |
def geometry_assemble_table(nw: NodeWrangler, **kwargs): | |
# Code generated using version 2.6.4 of the node_transpiler | |
generatetabletop = nw.new_node( | |
nodegroup_generate_table_top().name, | |
input_kwargs={ | |
"Thickness": kwargs["Top Thickness"], | |
"N-gon": kwargs["Top Profile N-gon"], | |
"Profile Width": kwargs["Top Profile Width"], | |
"Aspect Ratio": kwargs["Top Profile Aspect Ratio"], | |
"Fillet Ratio": kwargs["Top Profile Fillet Ratio"], | |
"Fillet Radius Vertical": kwargs["Top Vertical Fillet Ratio"], | |
}, | |
) | |
tabletop_instance = nw.new_node( | |
Nodes.Transform, | |
input_kwargs={ | |
"Geometry": generatetabletop, | |
"Translation": (0.0000, 0.0000, kwargs["Top Height"]), | |
}, | |
) | |
tabletop_instance = nw.new_node( | |
Nodes.SetMaterial, | |
input_kwargs={"Geometry": tabletop_instance, "Material": kwargs["TopMaterial"]}, | |
) | |
legs = nw.new_node(geometry_create_legs(**kwargs).name) | |
join_geometry = nw.new_node( | |
Nodes.JoinGeometry, input_kwargs={"Geometry": [tabletop_instance, legs]} | |
) | |
group_output = nw.new_node( | |
Nodes.GroupOutput, | |
input_kwargs={"Geometry": join_geometry}, | |
attrs={"is_active_output": True}, | |
) | |
class TableDiningFactory(AssetFactory): | |
def __init__(self, factory_seed, coarse=False, dimensions=None): | |
super(TableDiningFactory, self).__init__(factory_seed, coarse=coarse) | |
self.dimensions = dimensions | |
self.get_params_dict() | |
self.leg_styles = ["single_stand", "square", "straight"] | |
with FixedSeed(factory_seed): | |
self.params = self.sample_parameters(dimensions) | |
# self.clothes_scatter = ClothesCover(factory_fn=blanket.BlanketFactory, width=log_uniform(.8, 1.2), | |
# size=uniform(.8, 1.2)) if uniform() < .3 else NoApply() | |
self.clothes_scatter = NoApply() | |
self.material_params, self.scratch, self.edge_wear = ( | |
self.get_material_params() | |
) | |
self.params.update(self.material_params) | |
def get_params_dict(self): | |
# list all the parameters (key:name, value: [type, range]) used in this generator | |
self.params_dict = { | |
"ngon": ["discrete", (4, 36)], | |
"dimension_x": ["continuous", (0.9, 2.2)], | |
"dimension_y": ["continuous", (0.9, 2.2)], | |
"dimension_z": ["continuous", (0.5, 0.9)], | |
"leg_style": ["discrete", (0, 1, 2)], | |
"leg_number": ["discrete", (1, 2, 4)], | |
"leg_ngon": ["discrete", (4, 12)], | |
"leg_diameter": ["continuous", (0, 1)], | |
"leg_height": ["continuous", (0.6, 2.0)], | |
"leg_curve_ctrl_pts0": ["continuous", (0, 1)], | |
"leg_curve_ctrl_pts1": ["continuous", (0, 1)], | |
"leg_curve_ctrl_pts2": ["continuous", (0, 1)], | |
"top_scale": ["continuous", (0.6, 0.8)], # leg start point relative position | |
"bottom_scale": ["continuous", (0.9, 1.3)], # leg end point relative position | |
"top_thickness": ["continuous", (0.02, 0.1)], | |
"top_profile_fillet_ratio": ["continuous", (-0.6, 0.6)], # table corner round / square | |
"top_vertical_fillet_ratio": ["continuous", (0.0, 0.2)], # table corner round / square | |
"strecher_relative_pos": ["continuous", (0.15, 0.8)], | |
"strecher_increament": ["discrete", (0, 1, 2)], | |
} | |
def get_material_params(self): | |
material_assignments = AssetList["TableDiningFactory"]() | |
params = { | |
"TopMaterial": material_assignments["top"].assign_material(), | |
"LegMaterial": material_assignments["leg"].assign_material(), | |
} | |
wrapped_params = { | |
k: surface.shaderfunc_to_material(v) for k, v in params.items() | |
} | |
scratch_prob, edge_wear_prob = material_assignments["wear_tear_prob"] | |
scratch, edge_wear = material_assignments["wear_tear"] | |
is_scratch = uniform() < scratch_prob | |
is_edge_wear = uniform() < edge_wear_prob | |
if not is_scratch: | |
scratch = None | |
if not is_edge_wear: | |
edge_wear = None | |
return wrapped_params, scratch, edge_wear | |
def sample_parameters(dimensions): | |
# not used in DI-PCG | |
if dimensions is None: | |
width = uniform(0.91, 1.16) | |
if uniform() < 0.7: | |
# oblong | |
length = uniform(1.4, 2.8) | |
else: | |
# approx square | |
length = width * normal(1, 0.1) | |
dimensions = (length, width, uniform(0.65, 0.85)) | |
# all in meters | |
x, y, z = dimensions | |
NGon = 4 | |
leg_style = choice(["straight", "single_stand", "square"], p=[0.5, 0.1, 0.4]) | |
# leg_style = choice(['straight']) | |
if leg_style == "single_stand": | |
leg_number = 2 | |
leg_diameter = uniform(0.22 * x, 0.28 * x) | |
leg_curve_ctrl_pts = [ | |
(0.0, uniform(0.1, 0.2)), | |
(0.5, uniform(0.1, 0.2)), | |
(0.9, uniform(0.2, 0.3)), | |
(1.0, 1.0), | |
] | |
top_scale = uniform(0.6, 0.7) | |
bottom_scale = 1.0 | |
elif leg_style == "square": | |
leg_number = 2 | |
leg_diameter = uniform(0.07, 0.10) | |
leg_curve_ctrl_pts = None | |
top_scale = 0.8 | |
bottom_scale = 1.0 | |
elif leg_style == "straight": | |
leg_diameter = uniform(0.05, 0.07) | |
leg_number = 4 | |
leg_curve_ctrl_pts = [ | |
(0.0, 1.0), | |
(0.4, uniform(0.85, 0.95)), | |
(1.0, uniform(0.4, 0.6)), | |
] | |
top_scale = 0.8 | |
bottom_scale = uniform(1.0, 1.2) | |
else: | |
raise NotImplementedError | |
top_thickness = uniform(0.03, 0.06) | |
parameters = { | |
"Top Profile N-gon": NGon, | |
"Top Profile Width": 1.414 * x, | |
"Top Profile Aspect Ratio": y / x, | |
"Top Profile Fillet Ratio": uniform(0.0, 0.02), | |
"Top Thickness": top_thickness, | |
"Top Vertical Fillet Ratio": uniform(0.1, 0.3), | |
# 'Top Material': choice(['marble', 'tiled_wood', 'metal', 'fabric'], p=[.3, .3, .2, .2]), | |
"Height": z, | |
"Top Height": z - top_thickness, | |
"Leg Number": leg_number, | |
"Leg Style": leg_style, | |
"Leg NGon": 4, | |
"Leg Placement Top Relative Scale": top_scale, | |
"Leg Placement Bottom Relative Scale": bottom_scale, | |
"Leg Height": 1.0, | |
"Leg Diameter": leg_diameter, | |
"Leg Curve Control Points": leg_curve_ctrl_pts, | |
# 'Leg Material': choice(['metal', 'wood', 'glass', 'plastic']), | |
"Strecher Relative Pos": uniform(0.2, 0.6), | |
"Strecher Increament": choice([0, 1, 2]), | |
} | |
return parameters | |
def fix_unused_params(self, params): | |
if params['leg_style'] == 0: | |
# single stand only allow 1 or 2 legs | |
if params['leg_number'] == 4: | |
params['leg_number'] = 2 | |
params['bottom_scale'] = 1.1 | |
params['strecher_increament'] = 1 | |
elif params['leg_style'] == 1: | |
params['leg_number'] = 2 | |
params['leg_curve_ctrl_pts0'] = 0.5 | |
params['leg_curve_ctrl_pts1'] = 0.5 | |
params['leg_curve_ctrl_pts2'] = 0.5 | |
params['bottom_scale'] = 1.1 | |
params['top_scale'] = 0.8 | |
params['strecher_increament'] = 1 | |
elif params['leg_style'] == 2: | |
params['leg_number'] = 4 | |
params['leg_curve_ctrl_pts0'] = 0.5 | |
params['top_scale'] = 0.8 | |
if params['ngon'] == 36: | |
params['top_profile_fillet_ratio'] = 0.0 | |
params['top_vertical_fillet_ratio'] = 0.0 | |
return params | |
def update_params(self, params): | |
x, y, z = params["dimension_x"], params["dimension_y"], params["dimension_z"] | |
NGon = params['ngon'] | |
leg_style = self.leg_styles[int(params['leg_style'])] | |
if leg_style == "single_stand": | |
leg_number = params['leg_number'] | |
if leg_number == 4: | |
leg_number = 2 | |
leg_diameter = (0.2 + 0.2 * params['leg_diameter']) * x | |
leg_curve_ctrl_pts = [ | |
(0.0, 0.1 + 0.8 * params['leg_curve_ctrl_pts0']), | |
(0.5, 0.1 + 0.8 * params['leg_curve_ctrl_pts1']), | |
(0.9, 0.2 + 0.8 * params['leg_curve_ctrl_pts2']), | |
(1.0, 1.0), | |
] | |
top_scale = params['top_scale'] | |
bottom_scale = 1.0 | |
strecher_increament = 1 | |
elif leg_style == "square": | |
leg_number = 2 | |
leg_diameter = 0.05 + 0.2 * params['leg_diameter'] | |
leg_curve_ctrl_pts = None | |
top_scale = 0.8 | |
bottom_scale = 1.0 | |
strecher_increament = 1 | |
elif leg_style == "straight": | |
leg_diameter = 0.05 + 0.2 * params['leg_diameter'] | |
leg_number = 4 | |
leg_curve_ctrl_pts = [ | |
(0.0, 1.0), | |
(0.4, 0.5 + 0.5 * params['leg_curve_ctrl_pts1']), | |
(1.0, 0.3 + 0.5 * params['leg_curve_ctrl_pts2']) | |
] | |
top_scale = 0.8 | |
bottom_scale = params['bottom_scale'] | |
strecher_increament = params["strecher_increament"] | |
else: | |
raise NotImplementedError | |
if params['ngon'] == 36: | |
top_profile_fillet_ratio = 0.0 | |
top_vertical_fillet_ratio = 0.0 | |
else: | |
top_profile_fillet_ratio = params['top_profile_fillet_ratio'] | |
top_vertical_fillet_ratio = params['top_vertical_fillet_ratio'] | |
top_thickness = params['top_thickness'] | |
parameters = { | |
"Top Profile N-gon": NGon, | |
"Top Profile Width": 1.414 * x, | |
"Top Profile Aspect Ratio": y / x, | |
"Top Profile Fillet Ratio": top_profile_fillet_ratio, | |
"Top Thickness": top_thickness, | |
"Top Vertical Fillet Ratio": top_vertical_fillet_ratio, | |
"Height": z, | |
"Top Height": z - top_thickness, | |
"Leg Number": leg_number, | |
"Leg Style": leg_style, | |
"Leg NGon": params['leg_ngon'], | |
"Leg Placement Top Relative Scale": top_scale, | |
"Leg Placement Bottom Relative Scale": bottom_scale, | |
"Leg Height": params['leg_height'], | |
"Leg Diameter": leg_diameter, | |
"Leg Curve Control Points": leg_curve_ctrl_pts, | |
"Strecher Relative Pos": params["strecher_relative_pos"], | |
"Strecher Increament": strecher_increament, | |
} | |
self.params.update(parameters) | |
self.clothes_scatter = NoApply() | |
self.material_params, self.scratch, self.edge_wear = ( | |
self.get_material_params() | |
) | |
self.params.update(self.material_params) | |
def create_asset(self, **params): | |
bpy.ops.mesh.primitive_plane_add( | |
size=2, | |
enter_editmode=False, | |
align="WORLD", | |
location=(0, 0, 0), | |
scale=(1, 1, 1), | |
) | |
obj = bpy.context.active_object | |
# surface.add_geomod(obj, geometry_assemble_table, apply=False, input_kwargs=self.params) | |
surface.add_geomod( | |
obj, geometry_assemble_table, apply=True, input_kwargs=self.params | |
) | |
tagging.tag_system.relabel_obj(obj) | |
assert tagging.tagged_face_mask(obj, {t.Subpart.SupportSurface}).sum() != 0 | |
return obj | |
def finalize_assets(self, assets): | |
if self.scratch: | |
self.scratch.apply(assets) | |
if self.edge_wear: | |
self.edge_wear.apply(assets) | |
# def finalize_assets(self, assets): | |
# self.clothes_scatter.apply(assets) | |
class SideTableFactory(TableDiningFactory): | |
def __init__(self, factory_seed, coarse=False, dimensions=None): | |
if dimensions is None: | |
w = 0.55 * normal(1, 0.05) | |
h = 0.95 * w * normal(1, 0.05) | |
dimensions = (w, w, h) | |
super().__init__(factory_seed, coarse=coarse, dimensions=dimensions) | |
class CoffeeTableFactory(TableDiningFactory): | |
def __init__(self, factory_seed, coarse=False, dimensions=None): | |
if dimensions is None: | |
dimensions = (uniform(1, 1.5), uniform(0.6, 0.9), uniform(0.4, 0.5)) | |
super().__init__(factory_seed, coarse=coarse, dimensions=dimensions) | |