Spaces:
Runtime error
Runtime error
| # 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 | |
| import numpy as np | |
| from numpy.random import choice, randint, uniform | |
| import infinigen | |
| import infinigen.core.util.blender as butil | |
| from infinigen.assets.material_assignments import AssetList | |
| from infinigen.assets.objects.table_decorations.utils import ( | |
| nodegroup_lofting, | |
| nodegroup_star_profile, | |
| ) | |
| from infinigen.core import surface | |
| from infinigen.core.nodes import node_utils | |
| from infinigen.core.nodes.node_wrangler import Nodes, NodeWrangler | |
| from infinigen.core.placement.factory import AssetFactory | |
| from infinigen.core.util.math import FixedSeed | |
| class VaseFactory(AssetFactory): | |
| def __init__(self, factory_seed, coarse=False, dimensions=None): | |
| super(VaseFactory, self).__init__(factory_seed, coarse=coarse) | |
| if dimensions is None: | |
| z = uniform(0.17, 0.5) | |
| x = z * uniform(0.3, 0.6) | |
| dimensions = (x, x, z) | |
| self.dimensions = dimensions | |
| self.get_params_dict() | |
| with FixedSeed(factory_seed): | |
| self.params = self.sample_parameters(dimensions) | |
| 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 = { | |
| "dimension_x": ["continuous", (0.05, 0.4)], | |
| "dimension_z": ["continuous", (0.2, 0.8)], | |
| "neck_scale": ["continuous", (0.15, 0.8)], | |
| "profile_inner_radius": ["continuous", (0.8, 1.2)], | |
| "profile_star_points": ["discrete", (2,3,4,5,6,7,8,9,10,16,18,20,22,24,26,28,30)], | |
| "top_scale": ["continuous", (0.6, 1.4)], | |
| "neck_mid_position": ["continuous", (0.5, 1.5)], | |
| "neck_position": ["continuous", (-0.2, 0.2)], | |
| "shoulder_position": ["continuous", (0.1, 0.8)], | |
| "shoulder_thickness": ["continuous", (0.1, 0.3)], | |
| "foot_scale": ["continuous", (0.2, 0.8)], | |
| "foot_height": ["continuous", (0.01, 0.1)], | |
| } | |
| def get_material_params(self): | |
| material_assignments = AssetList["VaseFactory"]() | |
| params = { | |
| "Material": material_assignments["surface"].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): | |
| # all in meters | |
| if dimensions is None: | |
| z = uniform(0.25, 0.40) | |
| x = uniform(0.2, 0.4) * z | |
| dimensions = (x, x, z) | |
| x, y, z = dimensions | |
| U_resolution = 64 | |
| V_resolution = 64 | |
| neck_scale = uniform(0.2, 0.8) | |
| parameters = { | |
| "Profile Inner Radius": choice([1.0, uniform(0.8, 1.0)]), | |
| "Profile Star Points": randint(16, U_resolution // 2 + 1), | |
| "U_resolution": U_resolution, | |
| "V_resolution": V_resolution, | |
| "Height": z, | |
| "Diameter": x, | |
| "Top Scale": neck_scale * uniform(0.8, 1.2), | |
| "Neck Mid Position": uniform(0.7, 0.95), | |
| "Neck Position": 0.5 * neck_scale + 0.5 + uniform(-0.05, 0.05), | |
| "Neck Scale": neck_scale, | |
| "Shoulder Position": uniform(0.3, 0.7), | |
| "Shoulder Thickness": uniform(0.1, 0.25), | |
| "Foot Scale": uniform(0.4, 0.6), | |
| "Foot Height": uniform(0.01, 0.1), | |
| } | |
| return parameters | |
| def fix_unused_params(self, params): | |
| return params | |
| def update_params(self, params): | |
| x, y, z = params["dimension_x"], params["dimension_x"], params["dimension_z"] | |
| U_resolution = 64 | |
| V_resolution = 64 | |
| neck_scale = params["neck_scale"] | |
| parameters = { | |
| "Profile Inner Radius": np.clip(params["profile_inner_radius"], 0.8, 1.0), | |
| "Profile Star Points": params["profile_star_points"], | |
| "U_resolution": U_resolution, | |
| "V_resolution": V_resolution, | |
| "Height": z, | |
| "Diameter": x, | |
| "Top Scale": neck_scale * params["top_scale"], | |
| "Neck Mid Position": params["neck_mid_position"], | |
| "Neck Position": 0.5 * neck_scale + 0.5 + params["neck_position"], | |
| "Neck Scale": neck_scale, | |
| "Shoulder Position": params["shoulder_position"], | |
| "Shoulder Thickness": params["shoulder_thickness"], | |
| "Foot Scale": params["foot_scale"], | |
| "Foot Height": params["foot_height"], | |
| } | |
| self.params.update(parameters) | |
| 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_vases, apply=True, input_kwargs=self.params) | |
| butil.modify_mesh(obj, "SOLIDIFY", apply=True, thickness=0.002) | |
| butil.modify_mesh(obj, "SUBSURF", apply=True, levels=2, render_levels=2) | |
| return obj | |
| def finalize_assets(self, assets): | |
| if self.scratch: | |
| self.scratch.apply(assets) | |
| if self.edge_wear: | |
| self.edge_wear.apply(assets) | |
| def nodegroup_vase_profile(nw: NodeWrangler): | |
| # Code generated using version 2.6.4 of the node_transpiler | |
| group_input = nw.new_node( | |
| Nodes.GroupInput, | |
| expose_input=[ | |
| ("NodeSocketGeometry", "Profile Curve", None), | |
| ("NodeSocketFloat", "Height", 0.0000), | |
| ("NodeSocketFloat", "Diameter", 0.0000), | |
| ("NodeSocketFloat", "Top Scale", 0.0000), | |
| ("NodeSocketFloat", "Neck Mid Position", 0.0000), | |
| ("NodeSocketFloat", "Neck Position", 0.5000), | |
| ("NodeSocketFloat", "Neck Scale", 0.0000), | |
| ("NodeSocketFloat", "Shoulder Position", 0.0000), | |
| ("NodeSocketFloat", "Shoulder Thickness", 0.0000), | |
| ("NodeSocketFloat", "Foot Scale", 0.0000), | |
| ("NodeSocketFloat", "Foot Height", 0.0000), | |
| ], | |
| ) | |
| combine_xyz_1 = nw.new_node( | |
| Nodes.CombineXYZ, input_kwargs={"Z": group_input.outputs["Height"]} | |
| ) | |
| multiply = nw.new_node( | |
| Nodes.Math, | |
| input_kwargs={ | |
| 0: group_input.outputs["Top Scale"], | |
| 1: group_input.outputs["Diameter"], | |
| }, | |
| attrs={"operation": "MULTIPLY"}, | |
| ) | |
| neck_top = nw.new_node( | |
| Nodes.Transform, | |
| input_kwargs={ | |
| "Geometry": group_input.outputs["Profile Curve"], | |
| "Translation": combine_xyz_1, | |
| "Scale": multiply, | |
| }, | |
| ) | |
| multiply_1 = nw.new_node( | |
| Nodes.Math, | |
| input_kwargs={ | |
| 0: group_input.outputs["Height"], | |
| 1: group_input.outputs["Neck Position"], | |
| }, | |
| attrs={"operation": "MULTIPLY"}, | |
| ) | |
| combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={"Z": multiply_1}) | |
| multiply_2 = nw.new_node( | |
| Nodes.Math, | |
| input_kwargs={ | |
| 0: group_input.outputs["Diameter"], | |
| 1: group_input.outputs["Neck Scale"], | |
| }, | |
| attrs={"operation": "MULTIPLY"}, | |
| ) | |
| neck = nw.new_node( | |
| Nodes.Transform, | |
| input_kwargs={ | |
| "Geometry": group_input.outputs["Profile Curve"], | |
| "Translation": combine_xyz, | |
| "Scale": multiply_2, | |
| }, | |
| ) | |
| subtract = nw.new_node( | |
| Nodes.Math, | |
| input_kwargs={0: 1.0000, 1: group_input.outputs["Neck Position"]}, | |
| attrs={"use_clamp": True, "operation": "SUBTRACT"}, | |
| ) | |
| multiply_add = nw.new_node( | |
| Nodes.Math, | |
| input_kwargs={ | |
| 0: subtract, | |
| 1: group_input.outputs["Neck Mid Position"], | |
| 2: group_input.outputs["Neck Position"], | |
| }, | |
| attrs={"operation": "MULTIPLY_ADD"}, | |
| ) | |
| multiply_3 = nw.new_node( | |
| Nodes.Math, | |
| input_kwargs={0: multiply_add, 1: group_input.outputs["Height"]}, | |
| attrs={"operation": "MULTIPLY"}, | |
| ) | |
| combine_xyz_2 = nw.new_node(Nodes.CombineXYZ, input_kwargs={"Z": multiply_3}) | |
| add = nw.new_node( | |
| Nodes.Math, | |
| input_kwargs={ | |
| 0: group_input.outputs["Neck Scale"], | |
| 1: group_input.outputs["Top Scale"], | |
| }, | |
| ) | |
| divide = nw.new_node( | |
| Nodes.Math, input_kwargs={0: add, 1: 2.0000}, attrs={"operation": "DIVIDE"} | |
| ) | |
| multiply_4 = nw.new_node( | |
| Nodes.Math, | |
| input_kwargs={0: group_input.outputs["Diameter"], 1: divide}, | |
| attrs={"operation": "MULTIPLY"}, | |
| ) | |
| neck_middle = nw.new_node( | |
| Nodes.Transform, | |
| input_kwargs={ | |
| "Geometry": group_input.outputs["Profile Curve"], | |
| "Translation": combine_xyz_2, | |
| "Scale": multiply_4, | |
| }, | |
| ) | |
| neck_geometry = nw.new_node( | |
| Nodes.JoinGeometry, input_kwargs={"Geometry": [neck, neck_middle, neck_top]} | |
| ) | |
| map_range = nw.new_node( | |
| Nodes.MapRange, | |
| input_kwargs={ | |
| "Value": group_input.outputs["Shoulder Position"], | |
| 3: group_input.outputs["Foot Height"], | |
| 4: group_input.outputs["Neck Position"], | |
| }, | |
| ) | |
| subtract_1 = nw.new_node( | |
| Nodes.Math, | |
| input_kwargs={ | |
| 0: group_input.outputs["Neck Position"], | |
| 1: group_input.outputs["Foot Height"], | |
| }, | |
| attrs={"operation": "SUBTRACT"}, | |
| ) | |
| multiply_5 = nw.new_node( | |
| Nodes.Math, | |
| input_kwargs={0: subtract_1, 1: group_input.outputs["Shoulder Thickness"]}, | |
| attrs={"operation": "MULTIPLY"}, | |
| ) | |
| add_1 = nw.new_node( | |
| Nodes.Math, input_kwargs={0: map_range.outputs["Result"], 1: multiply_5} | |
| ) | |
| minimum = nw.new_node( | |
| Nodes.Math, | |
| input_kwargs={0: add_1, 1: group_input.outputs["Neck Position"]}, | |
| attrs={"operation": "MINIMUM"}, | |
| ) | |
| multiply_6 = nw.new_node( | |
| Nodes.Math, | |
| input_kwargs={0: minimum, 1: group_input.outputs["Height"]}, | |
| attrs={"operation": "MULTIPLY"}, | |
| ) | |
| combine_xyz_3 = nw.new_node(Nodes.CombineXYZ, input_kwargs={"Z": multiply_6}) | |
| body_top = nw.new_node( | |
| Nodes.Transform, | |
| input_kwargs={ | |
| "Geometry": group_input.outputs["Profile Curve"], | |
| "Translation": combine_xyz_3, | |
| "Scale": group_input.outputs["Diameter"], | |
| }, | |
| ) | |
| subtract_2 = nw.new_node( | |
| Nodes.Math, | |
| input_kwargs={0: map_range.outputs["Result"], 1: multiply_5}, | |
| attrs={"operation": "SUBTRACT"}, | |
| ) | |
| maximum = nw.new_node( | |
| Nodes.Math, | |
| input_kwargs={0: subtract_2, 1: group_input.outputs["Foot Height"]}, | |
| attrs={"operation": "MAXIMUM"}, | |
| ) | |
| multiply_7 = nw.new_node( | |
| Nodes.Math, | |
| input_kwargs={0: maximum, 1: group_input.outputs["Height"]}, | |
| attrs={"operation": "MULTIPLY"}, | |
| ) | |
| combine_xyz_5 = nw.new_node(Nodes.CombineXYZ, input_kwargs={"Z": multiply_7}) | |
| body_bottom = nw.new_node( | |
| Nodes.Transform, | |
| input_kwargs={ | |
| "Geometry": group_input.outputs["Profile Curve"], | |
| "Translation": combine_xyz_5, | |
| "Scale": group_input.outputs["Diameter"], | |
| }, | |
| ) | |
| body_geometry = nw.new_node( | |
| Nodes.JoinGeometry, input_kwargs={"Geometry": [body_bottom, body_top]} | |
| ) | |
| multiply_8 = nw.new_node( | |
| Nodes.Math, | |
| input_kwargs={ | |
| 0: group_input.outputs["Foot Height"], | |
| 1: group_input.outputs["Height"], | |
| }, | |
| attrs={"operation": "MULTIPLY"}, | |
| ) | |
| combine_xyz_4 = nw.new_node(Nodes.CombineXYZ, input_kwargs={"Z": multiply_8}) | |
| multiply_9 = nw.new_node( | |
| Nodes.Math, | |
| input_kwargs={ | |
| 0: group_input.outputs["Diameter"], | |
| 1: group_input.outputs["Foot Scale"], | |
| }, | |
| attrs={"operation": "MULTIPLY"}, | |
| ) | |
| foot_top = nw.new_node( | |
| Nodes.Transform, | |
| input_kwargs={ | |
| "Geometry": group_input, | |
| "Translation": combine_xyz_4, | |
| "Scale": multiply_9, | |
| }, | |
| ) | |
| foot_bottom = nw.new_node( | |
| Nodes.Transform, input_kwargs={"Geometry": group_input, "Scale": multiply_9} | |
| ) | |
| foot_geometry = nw.new_node( | |
| Nodes.JoinGeometry, input_kwargs={"Geometry": [foot_bottom, foot_top]} | |
| ) | |
| join_geometry_2 = nw.new_node( | |
| Nodes.JoinGeometry, | |
| input_kwargs={"Geometry": [foot_geometry, body_geometry, neck_geometry]}, | |
| ) | |
| group_output = nw.new_node( | |
| Nodes.GroupOutput, | |
| input_kwargs={"Geometry": join_geometry_2}, | |
| attrs={"is_active_output": True}, | |
| ) | |
| def geometry_vases(nw: NodeWrangler, **kwargs): | |
| # Code generated using version 2.6.4 of the node_transpiler | |
| starprofile = nw.new_node( | |
| nodegroup_star_profile().name, | |
| input_kwargs={ | |
| "Resolution": kwargs["U_resolution"], | |
| "Points": kwargs["Profile Star Points"], | |
| "Inner Radius": kwargs["Profile Inner Radius"], | |
| }, | |
| ) | |
| vaseprofile = nw.new_node( | |
| nodegroup_vase_profile().name, | |
| input_kwargs={ | |
| "Profile Curve": starprofile.outputs["Curve"], | |
| "Height": kwargs["Height"], | |
| "Diameter": kwargs["Diameter"], | |
| "Top Scale": kwargs["Top Scale"], | |
| "Neck Mid Position": kwargs["Neck Mid Position"], | |
| "Neck Position": kwargs["Neck Position"], | |
| "Neck Scale": kwargs["Neck Scale"], | |
| "Shoulder Position": kwargs["Shoulder Position"], | |
| "Shoulder Thickness": kwargs["Shoulder Thickness"], | |
| "Foot Scale": kwargs["Foot Scale"], | |
| "Foot Height": kwargs["Foot Height"], | |
| }, | |
| ) | |
| lofting = nw.new_node( | |
| nodegroup_lofting().name, | |
| input_kwargs={ | |
| "Profile Curves": vaseprofile, | |
| "U Resolution": 64, | |
| "V Resolution": 64, | |
| }, | |
| ) | |
| delete_geometry = nw.new_node( | |
| Nodes.DeleteGeometry, | |
| input_kwargs={ | |
| "Geometry": lofting.outputs["Geometry"], | |
| "Selection": lofting.outputs["Top"], | |
| }, | |
| ) | |
| set_material = nw.new_node( | |
| Nodes.SetMaterial, | |
| input_kwargs={"Geometry": delete_geometry, "Material": kwargs["Material"]}, | |
| ) | |
| group_output = nw.new_node( | |
| Nodes.GroupOutput, | |
| input_kwargs={"Geometry": set_material}, | |
| attrs={"is_active_output": True}, | |
| ) | |